<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  
  <title>Hexo</title>
  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
  <meta name="description">
<meta property="og:type" content="website">
<meta property="og:title" content="Hexo">
<meta property="og:url" content="http://yoursite.com/page/15/index.html">
<meta property="og:site_name" content="Hexo">
<meta property="og:description">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="Hexo">
<meta name="twitter:description">
  
    <link rel="alternative" href="/atom.xml" title="Hexo" type="application/atom+xml">
  
  
    <link rel="icon" href="/favicon.png">
  
  <link href="//fonts.googleapis.com/css?family=Source+Code+Pro" rel="stylesheet" type="text/css">
  <link rel="stylesheet" href="/css/style.css" type="text/css">
  

</head>
<body>
  <div id="container">
    <div id="wrap">
      <header id="header">
  <div id="banner"></div>
  <div id="header-outer" class="outer">
    <div id="header-title" class="inner">
      <h1 id="logo-wrap">
        <a href="/" id="logo">Hexo</a>
      </h1>
      
    </div>
    <div id="header-inner" class="inner">
      <nav id="main-nav">
        <a id="main-nav-toggle" class="nav-icon"></a>
        
          <a class="main-nav-link" href="/">Home</a>
        
          <a class="main-nav-link" href="/archives">Archives</a>
        
      </nav>
      <nav id="sub-nav">
        
          <a id="nav-rss-link" class="nav-icon" href="/atom.xml" title="RSS Feed"></a>
        
        <a id="nav-search-btn" class="nav-icon" title="Search"></a>
      </nav>
      <div id="search-form-wrap">
        <form action="//google.com/search" method="get" accept-charset="UTF-8" class="search-form"><input type="search" name="q" results="0" class="search-form-input" placeholder="Search"><button type="submit" class="search-form-submit">&#xF002;</button><input type="hidden" name="sitesearch" value="http://yoursite.com"></form>
      </div>
    </div>
  </div>
</header>
      <div class="outer">
        <section id="main">
  
    <article id="post-rpc/4.RPC系列之HttpInvoker源码分析" class="article article-type-post" itemscope itemprop="blogPost">
  <div class="article-meta">
    <a href="/2015/12/01/rpc/4.RPC系列之HttpInvoker源码分析/" class="article-date">
  <time datetime="2015-11-30T20:00:00.000Z" itemprop="datePublished">2015-12-01</time>
</a>
    
  <div class="article-category">
    <a class="article-category-link" href="/categories/rpc/">rpc</a>
  </div>

  </div>
  <div class="article-inner">
    
    
      <header class="article-header">
        
  
    <h1 itemprop="name">
      <a class="article-title" href="/2015/12/01/rpc/4.RPC系列之HttpInvoker源码分析/">RPC系列四之HttpInvoker源码分析</a>
    </h1>
  

      </header>
    
    <div class="article-entry" itemprop="articleBody">
      
        <h2 id="u7B80_u4ECB"><a href="#u7B80_u4ECB" class="headerlink" title="简介"></a>简介</h2><p>　　前面介绍了hessian的实现原理和与spring的集成方式。事实上，spring本身就为我们提供了一个基于http的RPC调用。与hessian一样，该实现也在spring-web的jar包中。此外，在该jar中还实现了jaxws，这里不再做介绍。</p>
<h2 id="u670D_u52A1_u7AEF_u5B9E_u73B0"><a href="#u670D_u52A1_u7AEF_u5B9E_u73B0" class="headerlink" title="服务端实现"></a>服务端实现</h2><p>　　与上篇文章一样，先搭建一个示例工程，再分析源码！这里建立一个maven工程，向pom.xml中添加如下信息：<br><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="title">dependencies</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="title">dependency</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="title">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="title">groupId</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="title">artifactId</span>&gt;</span>spring-boot-starter-web<span class="tag">&lt;/<span class="title">artifactId</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="title">version</span>&gt;</span>1.2.4.RELEASE<span class="tag">&lt;/<span class="title">version</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="title">dependency</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="title">dependencies</span>&gt;</span></span><br></pre></td></tr></table></figure></p>
<p>　　服务接口与实现类与上一篇文章汇总介绍的一致，这里不再赘述。下面定义一个ServerConfig类和启动类，如下所示：<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><span class="line"><span class="annotation">@Configuration</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">ServerConfig</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="annotation">@Bean</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> MyService <span class="title">myService</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> MySeriviceImpl();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="annotation">@Bean</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> MyServiceServerInterceptor <span class="title">serverInterceptor</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> MyServiceServerInterceptor();</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="annotation">@Bean</span>(name = <span class="string">"/hello2"</span>)</span><br><span class="line">    <span class="function">HttpInvokerServiceExporter <span class="title">httpInvokerServiceExporter</span><span class="params">(MyService myService, MyServiceServerInterceptor serverInterceptor)</span></span>&#123;</span><br><span class="line">        HttpInvokerServiceExporter exporter = <span class="keyword">new</span> HttpInvokerServiceExporter();</span><br><span class="line">        exporter.setService(myService);</span><br><span class="line">        exporter.setServiceInterface(MyService.class);</span><br><span class="line">        exporter.setInterceptors(<span class="keyword">new</span> Object[]&#123;serverInterceptor&#125;);</span><br><span class="line">        <span class="keyword">return</span> exporter;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="annotation">@SpringBootApplication</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">HttpInvokerApplication</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        SpringApplication springApplication = <span class="keyword">new</span> SpringApplication(HessianApplication.class);</span><br><span class="line">        springApplication.run(args);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>　　可以看出，服务端实现基本上与hessian的配置一致，只是将<strong>HessianServiceExporter</strong>改为了<strong>HttpInvokerServiceExporter</strong>。启动服务即可，此时服务的访问地址为：<a href="http://localhost:8080/hello2" target="_blank" rel="external">http://localhost:8080/hello2</a></p>
<h2 id="u5BA2_u6237_u7AEF_u5B9E_u73B0"><a href="#u5BA2_u6237_u7AEF_u5B9E_u73B0" class="headerlink" title="客户端实现"></a>客户端实现</h2><p>　　与spring+hessian一样，只需要定义一个ClientConfig和启动类SpringClient。<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><span class="line"><span class="annotation">@Configuration</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">ClientConfig</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="annotation">@Bean</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> HttpInvokerProxyFactoryBean <span class="title">httpInvokerProxyFactoryBean</span><span class="params">()</span></span>&#123;</span><br><span class="line">        HttpInvokerProxyFactoryBean bean = <span class="keyword">new</span> HttpInvokerProxyFactoryBean();</span><br><span class="line">        bean.setServiceUrl(<span class="string">"http://localhost:8080/hello2"</span>);</span><br><span class="line">        bean.setServiceInterface(MyService.class);</span><br><span class="line">        <span class="keyword">return</span> bean;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="annotation">@SpringBootApplication</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">SpringClient</span> <span class="keyword">implements</span> <span class="title">CommandLineRunner</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//@Autowired</span></span><br><span class="line">    <span class="comment">//ApplicationContext applicationContext;</span></span><br><span class="line">    <span class="annotation">@Autowired</span></span><br><span class="line">    MyService service;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">        SpringApplication springApplication = <span class="keyword">new</span> SpringApplication(SpringClient.class);</span><br><span class="line">        <span class="comment">//springApplication.addListeners(new ApplicationContextAware());</span></span><br><span class="line">        springApplication.run(args);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="annotation">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">(String... args)</span> <span class="keyword">throws</span> Exception </span>&#123;</span><br><span class="line">        <span class="comment">/*MyService myService = applicationContext.getBean(MyService.class);*/</span></span><br><span class="line">        System.out.println(service.doSomething(<span class="string">"xixixixi"</span>));</span><br><span class="line">        System.out.println(<span class="string">"ok!"</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>　　可以看出，客户端实现基本上与hessian的配置一致，只是将<strong>HessianProxyFactoryBean</strong>改为了<strong>HttpInvokerProxyFactoryBean</strong>。</p>
<h2 id="u670D_u52A1_u7AEF_u6E90_u7801_u5206_u6790"><a href="#u670D_u52A1_u7AEF_u6E90_u7801_u5206_u6790" class="headerlink" title="服务端源码分析"></a>服务端源码分析</h2><p>　　在ServerConfig类的实现中，我们可以看到，最重要的莫过于类HttpInvokerServiceExporter。初始化该类时，我们传入了实现类的一个实例，并指定了对应的接口，与hessian的初始化类似。下面我们进入HttpInvokerServiceExporter源码（在spring-web包中），核心代码如下：<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">HttpInvokerServiceExporter</span> <span class="keyword">extends</span> <span class="title">RemoteInvocationSerializingExporter</span></span><br><span class="line">		<span class="keyword">implements</span> <span class="title">HttpRequestHandler</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">	<span class="annotation">@Override</span></span><br><span class="line">	<span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">handleRequest</span><span class="params">(HttpServletRequest request, HttpServletResponse response)</span></span><br><span class="line">			<span class="keyword">throws</span> ServletException, IOException </span>&#123;</span><br><span class="line">		<span class="keyword">try</span> &#123;</span><br><span class="line">			RemoteInvocation invocation = readRemoteInvocation(request);</span><br><span class="line">			RemoteInvocationResult result = invokeAndCreateResult(invocation, getProxy());</span><br><span class="line">			writeRemoteInvocationResult(request, response, result);</span><br><span class="line">		&#125;<span class="keyword">catch</span> (ClassNotFoundException ex) &#123;</span><br><span class="line">			<span class="keyword">throw</span> <span class="keyword">new</span> NestedServletException(<span class="string">"Class not found during deserialization"</span>, ex);</span><br><span class="line">		&#125;</span><br><span class="line">	&#125;</span><br><span class="line">	...</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>　　服务端处理客户端的请求主要包括三步：<br>　　1. 每次请求到达时调用方法handleRequest，最终都会将HttpServletRequest的inputStream解析成RemoteInvocation，该类封装了请求的方法名，方法参数类型和参数值。<br>　　2. 接着调用invokeAndCreateResult，该方法是在其父类RemoteInvocationSerializingExporter中实现的，关键代码如下。可以看到，最后实际是由DefaultRemoteInvocationExecutor完成的，执行RemoteInvocation中的方法并返回结果，并将结果封装成RemoteInvocationResult。<br>　　3. 最后将RemoteInvocationResult序列化，写入HttpServletResponse的输出流中<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">abstract</span> <span class="class"><span class="keyword">class</span> <span class="title">RemoteInvocationBasedExporter</span> <span class="keyword">extends</span> <span class="title">RemoteExporter</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">	<span class="keyword">private</span> RemoteInvocationExecutor remoteInvocationExecutor = <span class="keyword">new</span> DefaultRemoteInvocationExecutor();</span><br><span class="line"></span><br><span class="line">	<span class="function"><span class="keyword">protected</span> Object <span class="title">invoke</span><span class="params">(RemoteInvocation invocation, Object targetObject)</span></span><br><span class="line">			<span class="keyword">throws</span> NoSuchMethodException, IllegalAccessException, InvocationTargetException </span>&#123;</span><br><span class="line">		<span class="keyword">return</span> remoteInvocationExecutor.invoke(invocation, targetObject);</span><br><span class="line">	&#125;</span><br><span class="line">	</span><br><span class="line">	<span class="function"><span class="keyword">protected</span> RemoteInvocationResult <span class="title">invokeAndCreateResult</span><span class="params">(RemoteInvocation invocation, Object targetObject)</span> </span>&#123;</span><br><span class="line">		<span class="keyword">try</span> &#123;</span><br><span class="line">			Object value = invoke(invocation, targetObject);</span><br><span class="line">			<span class="keyword">return</span> <span class="keyword">new</span> RemoteInvocationResult(value);</span><br><span class="line">		&#125;</span><br><span class="line">		<span class="keyword">catch</span> (Throwable ex) &#123;</span><br><span class="line">			<span class="keyword">return</span> <span class="keyword">new</span> RemoteInvocationResult(ex);</span><br><span class="line">		&#125;</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">DefaultRemoteInvocationExecutor</span> <span class="keyword">implements</span> <span class="title">RemoteInvocationExecutor</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">	<span class="annotation">@Override</span></span><br><span class="line">	<span class="function"><span class="keyword">public</span> Object <span class="title">invoke</span><span class="params">(RemoteInvocation invocation, Object targetObject)</span></span><br><span class="line">			<span class="keyword">throws</span> NoSuchMethodException, IllegalAccessException, InvocationTargetException</span>&#123;</span><br><span class="line">		<span class="keyword">return</span> invocation.invoke(targetObject);</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<h2 id="u5BA2_u6237_u7AEF_u6E90_u7801_u5206_u6790"><a href="#u5BA2_u6237_u7AEF_u6E90_u7801_u5206_u6790" class="headerlink" title="客户端源码分析"></a>客户端源码分析</h2><p>　　在客户端代码中，最重要的则为HttpInvokerProxyFactoryBean，具体的执行则是由其父类HttpInvokerClientInterceptor完成，关键代码如下：<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">HttpInvokerProxyFactoryBean</span> <span class="keyword">extends</span> <span class="title">HttpInvokerClientInterceptor</span> <span class="keyword">implements</span> <span class="title">FactoryBean</span>&lt;<span class="title">Object</span>&gt; </span>&#123;</span><br><span class="line"></span><br><span class="line">	<span class="keyword">private</span> Object serviceProxy;</span><br><span class="line"></span><br><span class="line">	<span class="annotation">@Override</span></span><br><span class="line">	<span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">afterPropertiesSet</span><span class="params">()</span> </span>&#123;</span><br><span class="line">		<span class="keyword">super</span>.afterPropertiesSet();</span><br><span class="line">		<span class="keyword">if</span> (getServiceInterface() == <span class="keyword">null</span>) &#123;</span><br><span class="line">			<span class="keyword">throw</span> <span class="keyword">new</span> IllegalArgumentException(<span class="string">"Property 'serviceInterface' is required"</span>);</span><br><span class="line">		&#125;</span><br><span class="line">		<span class="keyword">this</span>.serviceProxy = <span class="keyword">new</span> ProxyFactory(getServiceInterface(), <span class="keyword">this</span>).getProxy(getBeanClassLoader());</span><br><span class="line">	&#125;</span><br><span class="line">	......</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">HttpInvokerClientInterceptor</span> <span class="keyword">extends</span> <span class="title">RemoteInvocationBasedAccessor</span></span><br><span class="line">		<span class="keyword">implements</span> <span class="title">MethodInterceptor</span>, <span class="title">HttpInvokerClientConfiguration</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">	<span class="keyword">private</span> String codebaseUrl;</span><br><span class="line"></span><br><span class="line">	<span class="keyword">private</span> HttpInvokerRequestExecutor httpInvokerRequestExecutor;</span><br><span class="line"></span><br><span class="line">	<span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setHttpInvokerRequestExecutor</span><span class="params">(HttpInvokerRequestExecutor httpInvokerRequestExecutor)</span> </span>&#123;</span><br><span class="line">		<span class="keyword">this</span>.httpInvokerRequestExecutor = httpInvokerRequestExecutor;</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">	<span class="function"><span class="keyword">public</span> HttpInvokerRequestExecutor <span class="title">getHttpInvokerRequestExecutor</span><span class="params">()</span> </span>&#123;</span><br><span class="line">		<span class="keyword">if</span> (<span class="keyword">this</span>.httpInvokerRequestExecutor == <span class="keyword">null</span>) &#123;</span><br><span class="line">			SimpleHttpInvokerRequestExecutor executor = <span class="keyword">new</span> SimpleHttpInvokerRequestExecutor();</span><br><span class="line">			executor.setBeanClassLoader(getBeanClassLoader());</span><br><span class="line">			<span class="keyword">this</span>.httpInvokerRequestExecutor = executor;</span><br><span class="line">		&#125;</span><br><span class="line">		<span class="keyword">return</span> <span class="keyword">this</span>.httpInvokerRequestExecutor;</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">	<span class="annotation">@Override</span></span><br><span class="line">	<span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">afterPropertiesSet</span><span class="params">()</span> </span>&#123;</span><br><span class="line">		<span class="keyword">super</span>.afterPropertiesSet();</span><br><span class="line">		getHttpInvokerRequestExecutor();</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">	<span class="annotation">@Override</span></span><br><span class="line">	<span class="function"><span class="keyword">public</span> Object <span class="title">invoke</span><span class="params">(MethodInvocation methodInvocation)</span> <span class="keyword">throws</span> Throwable </span>&#123;</span><br><span class="line">		RemoteInvocation invocation = createRemoteInvocation(methodInvocation);</span><br><span class="line">		RemoteInvocationResult result = executeRequest(invocation, methodInvocation);</span><br><span class="line">		<span class="keyword">return</span> recreateRemoteInvocationResult(result);</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">	<span class="function"><span class="keyword">protected</span> RemoteInvocationResult <span class="title">executeRequest</span><span class="params">(</span><br><span class="line">			RemoteInvocation invocation, MethodInvocation originalInvocation)</span> <span class="keyword">throws</span> Exception </span>&#123;</span><br><span class="line">		<span class="keyword">return</span> executeRequest(invocation);</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">	<span class="function"><span class="keyword">protected</span> RemoteInvocationResult <span class="title">executeRequest</span><span class="params">(RemoteInvocation invocation)</span> <span class="keyword">throws</span> Exception </span>&#123;</span><br><span class="line">		<span class="keyword">return</span> getHttpInvokerRequestExecutor().executeRequest(<span class="keyword">this</span>, invocation);</span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>　　客户端的执行步骤主要包括：<br>　　1. 每次客户端发起请求时，实际会执行HttpInvokerClientInterceptor的invoke方法，该方法会先将请求封装成RemoteInvocation<br>　　2. 接着再执行executeRequest方法，实际上最后调用了SimpleHttpInvokerRequestExecutor的executeRequest方法。该类会将RemoteInvocation序列化，并发起网络请求，将序列化数据写入到输出流中<br>　　3. 网络请求完成后，将返回结果反序列化成RemoteInvocationResult，如果RemoteInvocationResult的exception属性不为空，则抛出错误，否则返回具体的值。</p>
<h2 id="u603B_u7ED3"><a href="#u603B_u7ED3" class="headerlink" title="总结"></a>总结</h2><p>　　到这里，我们就完成了全部的分析的过程。可以看到基本上与hessian一致。但是HttpInvoker的不足之处便是其序列化采用了JDK提供的方式，在数据量上偏大。示例代码下载：<a href="/code/http-invoker.zip">http-invoker.zip</a></p>
<h2 id="u53C2_u8003_u8D44_u6599"><a href="#u53C2_u8003_u8D44_u6599" class="headerlink" title="参考资料"></a>参考资料</h2><p><a href="http://blog.csdn.net/java2000_wl/article/details/7441212" target="_blank" rel="external">http://blog.csdn.net/java2000_wl/article/details/7441212</a></p>

      
    </div>
    <footer class="article-footer">
      <a data-url="http://yoursite.com/2015/12/01/rpc/4.RPC系列之HttpInvoker源码分析/" data-id="cijzzpv3f002d1cfsg3pa8lz4" class="article-share-link">Share</a>
      
      
  <ul class="article-tag-list"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/hessisan/">hessisan</a></li><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/java/">java</a></li><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/rpc/">rpc</a></li><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/spring/">spring</a></li></ul>

    </footer>
  </div>
  
</article>


  
    <article id="post-linux/3.Linux系列之常用环境变量" class="article article-type-post" itemscope itemprop="blogPost">
  <div class="article-meta">
    <a href="/2015/12/01/linux/3.Linux系列之常用环境变量/" class="article-date">
  <time datetime="2015-11-30T19:00:00.000Z" itemprop="datePublished">2015-12-01</time>
</a>
    
  <div class="article-category">
    <a class="article-category-link" href="/categories/linux/">linux</a>
  </div>

  </div>
  <div class="article-inner">
    
    
      <header class="article-header">
        
  
    <h1 itemprop="name">
      <a class="article-title" href="/2015/12/01/linux/3.Linux系列之常用环境变量/">Linux系列三之常用环境变量</a>
    </h1>
  

      </header>
    
    <div class="article-entry" itemprop="articleBody">
      
        <p>/etc/profile文件修改之后，为使其生效，可运行source /etc/profile</p>
<p>在/etc/profile文件末尾，添加如下内容</p>
<p>export JAVA_HOME=/usr/dev/jdk<br>export CLASSPATH=.:$JAVA_HOME/lib:$CLASSPATH<br>export PATH=$JAVA_HOME/bin:$JAVA_HOME:$PATH</p>
<p>export ZOOKEEPER_HOME=/usr/local/zookeeper-3.4.6<br>export PATH=$ZOOKEEPER_HOME/bin:$PATH</p>
<p>export STORM_HOME=/usr/local/apache-storm-0.9.4<br>export PATH=$STORM_HOME/bin:$PATH</p>
<p>export M3_HOME=/usr/dev/apache-maven-3.0.5<br>export M3=$M3_HOME/bin<br>export MAVEN_OPTS=”-Xms256m -Xmx512m”<br>export PATH=$M3:$PATH</p>
<p>export ANT_HOME=/usr/dev/apache-ant-1.9.2<br>export PATH=$PATH:$ANT_HOME/bin<br>export CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar</p>
<p>export TOMCAT_HOME=/usr/dev/apache-tomcat</p>
<p>#export NODEJS_HOME=/usr/dev/nodejs-0.10.23</p>
<p>#export PATH=$NODEJS_HOME/bin:$PATH</p>
<p>#export NODE_PATH=$NODEJS_HOME:$NODEJS_HOME/lib/node_modules</p>
<p>export HIVE_HOME=/usr/dev/hive-0.12.0-bin<br>export PATH=$HIVE_HOME/bin:$PATH</p>
<p>export HADOOP_HOME=/usr/dev/hadoop-2.2.0<br>export PATH=$PATH:$HADOOP_HOME/bin</p>
<p>export FINDBUGS_HOME=/usr/dev/findbugs-3.0.0-rc2<br>export PATH=$PATH:$FINDBUGS_HOME/bin</p>
<p>export PROTOC_HOME=/usr/dev/protoc<br>export PATH=$PATH:$PROTOC_HOME/bin</p>
<p>export PIG_HOME=/usr/dev/pig-0.13.0<br>export CLASSPATH=/usr/dev/hadoop-2.2.0/etc/hadoop:$CLASSPATH<br>export PATH=$PATH:$PIG_HOME/bin</p>

      
    </div>
    <footer class="article-footer">
      <a data-url="http://yoursite.com/2015/12/01/linux/3.Linux系列之常用环境变量/" data-id="cijzzpvco00bn1cfsdagvczvn" class="article-share-link">Share</a>
      
      
  <ul class="article-tag-list"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/linux/">linux</a></li></ul>

    </footer>
  </div>
  
</article>


  
    <article id="post-rpc/3.RPC系列之Hessian+Spring源码分析" class="article article-type-post" itemscope itemprop="blogPost">
  <div class="article-meta">
    <a href="/2015/12/01/rpc/3.RPC系列之Hessian+Spring源码分析/" class="article-date">
  <time datetime="2015-11-30T19:00:00.000Z" itemprop="datePublished">2015-12-01</time>
</a>
    
  <div class="article-category">
    <a class="article-category-link" href="/categories/rpc/">rpc</a>
  </div>

  </div>
  <div class="article-inner">
    
    
      <header class="article-header">
        
  
    <h1 itemprop="name">
      <a class="article-title" href="/2015/12/01/rpc/3.RPC系列之Hessian+Spring源码分析/">RPC系列三之Hessian+Spring源码分析</a>
    </h1>
  

      </header>
    
    <div class="article-entry" itemprop="articleBody">
      
        <h2 id="u670D_u52A1_u7AEF_u5B9E_u73B0"><a href="#u670D_u52A1_u7AEF_u5B9E_u73B0" class="headerlink" title="服务端实现"></a>服务端实现</h2><p>　　与之前一样，先搭建一个基于spring boot的示例工程，再分析源码！首先向pom.xml中添加如下信息：<br><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="title">dependencies</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="title">dependency</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="title">groupId</span>&gt;</span>com.caucho<span class="tag">&lt;/<span class="title">groupId</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="title">artifactId</span>&gt;</span>hessian<span class="tag">&lt;/<span class="title">artifactId</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="title">version</span>&gt;</span>4.0.38<span class="tag">&lt;/<span class="title">version</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="title">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="title">dependency</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="title">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="title">groupId</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="title">artifactId</span>&gt;</span>spring-boot-starter-web<span class="tag">&lt;/<span class="title">artifactId</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="title">version</span>&gt;</span>1.2.4.RELEASE<span class="tag">&lt;/<span class="title">version</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="title">dependency</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="title">dependencies</span>&gt;</span></span><br></pre></td></tr></table></figure></p>
<p>　　服务接口与实现类与上一篇文章汇总介绍的一致，这里不再赘述。因为要与spring boot结合，下面定义一个HessianServerConfig类和启动类，如下所示：<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="annotation">@Configuration</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">HessianServerConfig</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="annotation">@Bean</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> MyService <span class="title">myService</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> MySeriviceImpl();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="annotation">@Bean</span>(name=<span class="string">"/hello"</span>)</span><br><span class="line">    <span class="function">HessianServiceExporter <span class="title">hessianServiceExporter</span><span class="params">(MyService myService)</span></span>&#123;</span><br><span class="line">        HessianServiceExporter exporter = <span class="keyword">new</span> HessianServiceExporter();</span><br><span class="line">        exporter.setService(myService);</span><br><span class="line">        exporter.setServiceInterface(MyService.class);</span><br><span class="line">        <span class="keyword">return</span> exporter;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="annotation">@SpringBootApplication</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">HessianApplication</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        SpringApplication springApplication = <span class="keyword">new</span> SpringApplication(HessianApplication.class);</span><br><span class="line">        springApplication.run(args);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>　　启动服务即可，此时服务的访问地址为：<a href="http://localhost:8080/hello" target="_blank" rel="external">http://localhost:8080/hello</a>，采用上一篇的Client类测试即可。</p>
<h2 id="u5BA2_u6237_u7AEF_u5B9E_u73B0"><a href="#u5BA2_u6237_u7AEF_u5B9E_u73B0" class="headerlink" title="客户端实现"></a>客户端实现</h2><p>　　下面我们介绍的客户端实现也采用spring boot的形式。与上文一样，只需要定义一个HessianClientConfig和启动类SpringClient。<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><span class="line"><span class="annotation">@Configuration</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">HessianClientConfig</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="annotation">@Bean</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> HessianProxyFactoryBean <span class="title">factory</span><span class="params">()</span></span>&#123;</span><br><span class="line">        HessianProxyFactoryBean bean = <span class="keyword">new</span> HessianProxyFactoryBean();</span><br><span class="line">        bean.setServiceUrl(<span class="string">"http://localhost:8080/hello"</span>);</span><br><span class="line">        bean.setServiceInterface(MyService.class);</span><br><span class="line">        <span class="keyword">return</span> bean;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="annotation">@SpringBootApplication</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">SpringClient</span> <span class="keyword">implements</span> <span class="title">CommandLineRunner</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//@Autowired</span></span><br><span class="line">    <span class="comment">//ApplicationContext applicationContext;</span></span><br><span class="line">    <span class="annotation">@Autowired</span></span><br><span class="line">    MyService service;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">        SpringApplication springApplication = <span class="keyword">new</span> SpringApplication(SpringClient.class);</span><br><span class="line">        <span class="comment">//springApplication.addListeners(new ApplicationContextAware());</span></span><br><span class="line">        springApplication.run(args);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="annotation">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">(String... args)</span> <span class="keyword">throws</span> Exception </span>&#123;</span><br><span class="line">        <span class="comment">/*MyService myService = applicationContext.getBean(MyService.class);*/</span></span><br><span class="line">        System.out.println(service.doSomething(<span class="string">"xixixixi"</span>));</span><br><span class="line">        System.out.println(<span class="string">"ok!"</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>　　运行该程序即可看到效果</p>
<h2 id="u670D_u52A1_u7AEF_u6E90_u7801_u5206_u6790"><a href="#u670D_u52A1_u7AEF_u6E90_u7801_u5206_u6790" class="headerlink" title="服务端源码分析"></a>服务端源码分析</h2><p>　　在HessianServerConfig类的实现中，我们可以看到，最重要的莫过于类HessianServiceExporter，初始化该类时，我们传入了实现类的一个实例，并指定了对应的接口。下面我们进入HessianServiceExporter源码（在spring-web包中），如下：<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">HessianServiceExporter</span> <span class="keyword">extends</span> <span class="title">HessianExporter</span> <span class="keyword">implements</span> <span class="title">HttpRequestHandler</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">	<span class="comment">/**</span><br><span class="line">	 * Processes the incoming Hessian request and creates a Hessian response.</span><br><span class="line">	 */</span></span><br><span class="line">	<span class="annotation">@Override</span></span><br><span class="line">	<span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">handleRequest</span><span class="params">(HttpServletRequest request, HttpServletResponse response)</span></span><br><span class="line">			<span class="keyword">throws</span> ServletException, IOException </span>&#123;</span><br><span class="line"></span><br><span class="line">		<span class="keyword">if</span> (!<span class="string">"POST"</span>.equals(request.getMethod())) &#123;</span><br><span class="line">			<span class="keyword">throw</span> <span class="keyword">new</span> HttpRequestMethodNotSupportedException(request.getMethod(),</span><br><span class="line">					<span class="keyword">new</span> String[] &#123;<span class="string">"POST"</span>&#125;, <span class="string">"HessianServiceExporter only supports POST requests"</span>);</span><br><span class="line">		&#125;</span><br><span class="line"></span><br><span class="line">		response.setContentType(CONTENT_TYPE_HESSIAN);</span><br><span class="line">		<span class="keyword">try</span> &#123;</span><br><span class="line">		  invoke(request.getInputStream(), response.getOutputStream());</span><br><span class="line">		&#125;</span><br><span class="line">		<span class="keyword">catch</span> (Throwable ex) &#123;</span><br><span class="line">		  <span class="keyword">throw</span> <span class="keyword">new</span> NestedServletException(<span class="string">"Hessian skeleton invocation failed"</span>, ex);</span><br><span class="line">		&#125;</span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>　　该类实现了一个方法handleRequest，该方法由接口HttpRequestHandler定义。下面我们进入HessianExporter的实现，这里贴出最核心的几个代码<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> com.caucho.hessian.server.HessianSkeleton;</span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">HessianExporter</span> <span class="keyword">extends</span> <span class="title">RemoteExporter</span> <span class="keyword">implements</span> <span class="title">InitializingBean</span> </span>&#123;</span><br><span class="line">	<span class="keyword">private</span> HessianSkeleton skeleton;</span><br><span class="line">	</span><br><span class="line">	<span class="annotation">@Override</span></span><br><span class="line">	<span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">afterPropertiesSet</span><span class="params">()</span> </span>&#123;</span><br><span class="line">		prepare();</span><br><span class="line">	&#125;</span><br><span class="line">	</span><br><span class="line">	<span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">prepare</span><span class="params">()</span> </span>&#123;</span><br><span class="line">		<span class="keyword">this</span>.skeleton = <span class="keyword">new</span> HessianSkeleton(getProxyForService(), getServiceInterface());</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">	<span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">invoke</span><span class="params">(InputStream inputStream, OutputStream outputStream)</span> <span class="keyword">throws</span> Throwable </span>&#123;</span><br><span class="line">		doInvoke(<span class="keyword">this</span>.skeleton, inputStream, outputStream);</span><br><span class="line">	&#125;</span><br><span class="line">	</span><br><span class="line">	<span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">doInvoke</span><span class="params">(HessianSkeleton skeleton, InputStream inputStream, OutputStream outputStream)</span> <span class="keyword">throws</span> Throwable </span>&#123;</span><br><span class="line">		ClassLoader originalClassLoader = overrideThreadContextClassLoader();</span><br><span class="line">		<span class="keyword">try</span> &#123;</span><br><span class="line">			InputStream isToUse = inputStream;</span><br><span class="line">			OutputStream osToUse = outputStream;</span><br><span class="line"></span><br><span class="line">			<span class="keyword">int</span> code = isToUse.read();</span><br><span class="line">			<span class="keyword">int</span> major;</span><br><span class="line">			<span class="keyword">int</span> minor;</span><br><span class="line"></span><br><span class="line">			AbstractHessianInput in;</span><br><span class="line">			AbstractHessianOutput out;</span><br><span class="line"></span><br><span class="line">			<span class="keyword">if</span> (code == <span class="string">'H'</span>) &#123;</span><br><span class="line">				<span class="comment">// Hessian 2.0 stream</span></span><br><span class="line">				major = isToUse.read();</span><br><span class="line">				minor = isToUse.read();</span><br><span class="line">				<span class="keyword">if</span> (major != <span class="number">0x02</span>) &#123;</span><br><span class="line">					<span class="keyword">throw</span> <span class="keyword">new</span> IOException(<span class="string">"Version "</span> + major + <span class="string">"."</span> + minor + <span class="string">" is not understood"</span>);</span><br><span class="line">				&#125;</span><br><span class="line">				in = <span class="keyword">new</span> Hessian2Input(isToUse);</span><br><span class="line">				out = <span class="keyword">new</span> Hessian2Output(osToUse);</span><br><span class="line">				in.readCall();</span><br><span class="line">			&#125;<span class="keyword">else</span> <span class="keyword">if</span> (code == <span class="string">'C'</span>) &#123;</span><br><span class="line">				<span class="comment">// Hessian 2.0 call... for some reason not handled in HessianServlet!</span></span><br><span class="line">				isToUse.reset();</span><br><span class="line">				in = <span class="keyword">new</span> Hessian2Input(isToUse);</span><br><span class="line">				out = <span class="keyword">new</span> Hessian2Output(osToUse);</span><br><span class="line">				in.readCall();</span><br><span class="line">			&#125;<span class="keyword">else</span> <span class="keyword">if</span> (code == <span class="string">'c'</span>) &#123;</span><br><span class="line">				<span class="comment">// Hessian 1.0 call</span></span><br><span class="line">				major = isToUse.read();</span><br><span class="line">				minor = isToUse.read();</span><br><span class="line">				in = <span class="keyword">new</span> HessianInput(isToUse);</span><br><span class="line">				<span class="keyword">if</span> (major &gt;= <span class="number">2</span>) &#123;</span><br><span class="line">					out = <span class="keyword">new</span> Hessian2Output(osToUse);</span><br><span class="line">				&#125;</span><br><span class="line">				<span class="keyword">else</span> &#123;</span><br><span class="line">					out = <span class="keyword">new</span> HessianOutput(osToUse);</span><br><span class="line">				&#125;</span><br><span class="line">			&#125;<span class="keyword">else</span> &#123;</span><br><span class="line">				<span class="keyword">throw</span> <span class="keyword">new</span> IOException(<span class="string">"Expected 'H'/'C' (Hessian 2.0) or 'c' (Hessian 1.0) in hessian input at "</span> + code);</span><br><span class="line">			&#125;</span><br><span class="line"></span><br><span class="line">			<span class="keyword">if</span> (<span class="keyword">this</span>.serializerFactory != <span class="keyword">null</span>) &#123;</span><br><span class="line">				in.setSerializerFactory(<span class="keyword">this</span>.serializerFactory);</span><br><span class="line">				out.setSerializerFactory(<span class="keyword">this</span>.serializerFactory);</span><br><span class="line">			&#125;</span><br><span class="line">			<span class="keyword">if</span> (<span class="keyword">this</span>.remoteResolver != <span class="keyword">null</span>) &#123;</span><br><span class="line">				in.setRemoteResolver(<span class="keyword">this</span>.remoteResolver);</span><br><span class="line">			&#125;</span><br><span class="line">			skeleton.invoke(in, out);</span><br><span class="line">		&#125;</span><br><span class="line">		<span class="keyword">finally</span> &#123;</span><br><span class="line">			resetThreadContextClassLoader(originalClassLoader);</span><br><span class="line">		&#125;</span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>　　可以看到，最后的解析工作主要还是由hessian提供的HessianSkeleton完成。事实上，传入HessianSkeleton构造方法的第一个参数为代理对象。下面我们看看getProxyForService方法的实现，这里只列出最关键的代码。<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">protected</span> Object <span class="title">getProxyForService</span><span class="params">()</span> </span>&#123;</span><br><span class="line">	ProxyFactory proxyFactory = <span class="keyword">new</span> ProxyFactory();</span><br><span class="line">	proxyFactory.addInterface(getServiceInterface());</span><br><span class="line">	<span class="comment">//添加一个拦截器RemoteInvocationTraceInterceptor，该拦截器实现了接口MethodInterceptor</span></span><br><span class="line">	<span class="keyword">if</span> (<span class="keyword">this</span>.registerTraceInterceptor != <span class="keyword">null</span> ?</span><br><span class="line">			<span class="keyword">this</span>.registerTraceInterceptor.booleanValue() : <span class="keyword">this</span>.interceptors == <span class="keyword">null</span>) &#123;</span><br><span class="line">		proxyFactory.addAdvice(<span class="keyword">new</span> RemoteInvocationTraceInterceptor(getExporterName()));</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="keyword">if</span> (<span class="keyword">this</span>.interceptors != <span class="keyword">null</span>) &#123;</span><br><span class="line">		AdvisorAdapterRegistry adapterRegistry = GlobalAdvisorAdapterRegistry.getInstance();</span><br><span class="line">		<span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; <span class="keyword">this</span>.interceptors.length; i++) &#123;</span><br><span class="line">			proxyFactory.addAdvisor(adapterRegistry.wrap(<span class="keyword">this</span>.interceptors[i]));</span><br><span class="line">		&#125;</span><br><span class="line">	&#125;</span><br><span class="line">	proxyFactory.setTarget(getService());</span><br><span class="line">	proxyFactory.setOpaque(<span class="keyword">true</span>);</span><br><span class="line">	<span class="keyword">return</span> proxyFactory.getProxy(getBeanClassLoader());</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>　　上述代码最重要的便是定义了一个ProxyFactory类的对象，并指定了接口、目标代理对象以及拦截器。最后返回的是一个代理对象（JDK动态代理实现）。以后单独介绍ProxyFactory和DefaultAopProxyFactory的实现原理。</p>
<h2 id="u5BA2_u6237_u7AEF_u6E90_u7801_u5206_u6790"><a href="#u5BA2_u6237_u7AEF_u6E90_u7801_u5206_u6790" class="headerlink" title="客户端源码分析"></a>客户端源码分析</h2><p>　　在客户端的代码中个，最重要的便是类HessianProxyFactoryBean，实现如下：<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">HessianProxyFactoryBean</span> <span class="keyword">extends</span> <span class="title">HessianClientInterceptor</span> <span class="keyword">implements</span> <span class="title">FactoryBean</span>&lt;<span class="title">Object</span>&gt; </span>&#123;</span><br><span class="line"></span><br><span class="line">	<span class="keyword">private</span> Object serviceProxy;</span><br><span class="line"></span><br><span class="line">	<span class="annotation">@Override</span></span><br><span class="line">	<span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">afterPropertiesSet</span><span class="params">()</span> </span>&#123;</span><br><span class="line">		<span class="keyword">super</span>.afterPropertiesSet();</span><br><span class="line">		<span class="keyword">this</span>.serviceProxy = <span class="keyword">new</span> ProxyFactory(getServiceInterface(), <span class="keyword">this</span>).getProxy(getBeanClassLoader());</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">	<span class="annotation">@Override</span></span><br><span class="line">	<span class="function"><span class="keyword">public</span> Object <span class="title">getObject</span><span class="params">()</span> </span>&#123;</span><br><span class="line">		<span class="keyword">return</span> <span class="keyword">this</span>.serviceProxy;</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">	<span class="annotation">@Override</span></span><br><span class="line">	<span class="keyword">public</span> Class&lt;?&gt; getObjectType() &#123;</span><br><span class="line">		<span class="keyword">return</span> getServiceInterface();</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">	<span class="annotation">@Override</span></span><br><span class="line">	<span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">isSingleton</span><span class="params">()</span> </span>&#123;</span><br><span class="line">		<span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>　　同样的，该类在初始化时，定义了一个ProxyFactory类的对象serviceProxy。由于该类实现了FactoryBean接口，所以获取bean时实际返回的是serviceProxy（由getObject方法返回）。<br>　　注意，ProxyFactory构造方法的第二个参数为Interceptor类型，初始化时传入的是this对象。实际上是由其父类HessianClientInterceptor实现了MethodInterceptor接口，下面给出HessianClientInterceptor类的关键代码<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">HessianClientInterceptor</span> <span class="keyword">extends</span> <span class="title">UrlBasedRemoteAccessor</span> <span class="keyword">implements</span> <span class="title">MethodInterceptor</span> </span>&#123;</span><br><span class="line">	<span class="comment">//注意，HessianProxyFactory为hessian提供的代理工厂</span></span><br><span class="line">	<span class="keyword">private</span> HessianProxyFactory proxyFactory = <span class="keyword">new</span> HessianProxyFactory();</span><br><span class="line"></span><br><span class="line">	<span class="keyword">private</span> Object hessianProxy;</span><br><span class="line"></span><br><span class="line">	<span class="annotation">@Override</span></span><br><span class="line">	<span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">afterPropertiesSet</span><span class="params">()</span> </span>&#123;</span><br><span class="line">		<span class="keyword">super</span>.afterPropertiesSet();</span><br><span class="line">		prepare();</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">prepare</span><span class="params">()</span> <span class="keyword">throws</span> RemoteLookupFailureException </span>&#123;</span><br><span class="line">		<span class="keyword">this</span>.hessianProxy = createHessianProxy(<span class="keyword">this</span>.proxyFactory);</span><br><span class="line">	&#125;</span><br><span class="line">	</span><br><span class="line">	<span class="function"><span class="keyword">protected</span> Object <span class="title">createHessianProxy</span><span class="params">(HessianProxyFactory proxyFactory)</span> <span class="keyword">throws</span> MalformedURLException </span>&#123;</span><br><span class="line">		<span class="keyword">return</span> proxyFactory.create(getServiceInterface(), getServiceUrl(), getBeanClassLoader());</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">	<span class="annotation">@Override</span></span><br><span class="line">	<span class="function"><span class="keyword">public</span> Object <span class="title">invoke</span><span class="params">(MethodInvocation invocation)</span> <span class="keyword">throws</span> Throwable </span>&#123;</span><br><span class="line">		ClassLoader originalClassLoader = overrideThreadContextClassLoader();</span><br><span class="line">		<span class="keyword">return</span> invocation.getMethod().invoke(<span class="keyword">this</span>.hessianProxy, invocation.getArguments());</span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<h2 id="u603B_u7ED3"><a href="#u603B_u7ED3" class="headerlink" title="总结"></a>总结</h2><p>　　到这里，我们可以看出：无论是服务端，还是客户端，都实现了spring都在hessian的实现外层，都增加了一个动态代理，并提供了拦截器的支持。在client端。程序中通过@Autowired注入的实际上是spring的代理，每次调用业务类方法时（这里指doSomething方法），<br>是由spring的代理调用hessian自带的客户端代理，进行网络请求。<br>　　注意：spring对hessian的服务端提供了拦截器。如果想在其客户端调用之前增加一个拦截器，则需要修改源码！服务端拦截器示例详见参考代码：<a href="/code/hessian-spring.zip">hessian-spring.zip</a>，针对本例拦截器的执行，spring源码关键处为org.springframework.aop.framework.JdkDynamicAopProxy类的invoke方法。</p>

      
    </div>
    <footer class="article-footer">
      <a data-url="http://yoursite.com/2015/12/01/rpc/3.RPC系列之Hessian+Spring源码分析/" data-id="cijzzpv3l002k1cfsh3iz43cw" class="article-share-link">Share</a>
      
      
  <ul class="article-tag-list"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/hessisan/">hessisan</a></li><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/java/">java</a></li><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/rpc/">rpc</a></li><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/spring/">spring</a></li></ul>

    </footer>
  </div>
  
</article>


  
    <article id="post-linux/2.Linux系列之tcp" class="article article-type-post" itemscope itemprop="blogPost">
  <div class="article-meta">
    <a href="/2015/12/01/linux/2.Linux系列之tcp/" class="article-date">
  <time datetime="2015-11-30T18:00:00.000Z" itemprop="datePublished">2015-12-01</time>
</a>
    
  <div class="article-category">
    <a class="article-category-link" href="/categories/linux/">linux</a>
  </div>

  </div>
  <div class="article-inner">
    
    
      <header class="article-header">
        
  
    <h1 itemprop="name">
      <a class="article-title" href="/2015/12/01/linux/2.Linux系列之tcp/">Linux系列二之tcp</a>
    </h1>
  

      </header>
    
    <div class="article-entry" itemprop="articleBody">
      
        <h2 id="tcp_u8FDE_u63A5_u72B6_u6001"><a href="#tcp_u8FDE_u63A5_u72B6_u6001" class="headerlink" title="tcp连接状态"></a>tcp连接状态</h2><ul>
<li>LISTEN：侦听来自远方的TCP端口的连接请求</li>
<li>SYN-SENT：在发送连接请求后等待匹配的连接请求</li>
<li>SYN-RECEIVED：在收到和发送一个连接请求后等待对方对连接请求的确认</li>
<li>ESTABLISHED：代表一个打开的连接</li>
<li>FIN-WAIT-1：等待远程TCP连接中断请求，或先前的连接中断请求的确认</li>
<li>FIN-WAIT-2：从远程TCP等待连接中断请求</li>
<li>CLOSE-WAIT：等待从本地用户发来的连接中断请求</li>
<li>CLOSING：等待远程TCP对连接中断的确认</li>
<li>LAST-ACK：等待原来的发向远程TCP的连接中断请求的确认</li>
<li>TIME-WAIT：等待足够的时间以确保远程TCP接收到连接中断请求的确认</li>
<li>CLOSED：没有任何连接状态<h2 id="TIME_WAIT"><a href="#TIME_WAIT" class="headerlink" title="TIME_WAIT"></a>TIME_WAIT</h2>　　根据TCP协议定义的3次握手断开连接规定，发起socket主动关闭的一方，socket将进入TIME_WAIT状态（在消息推送esb的测试中，esb压测测试程序（esb.jar）运行所在的服务器会产生大量的TIME_WAIT，netstat -np），而被动关闭一方则转入CLOSED状态。TIME_WAIT状态将持续2个MSL(Max Segment Lifetime)。<strong>TIME_WAIT状态下的socket不能被回收使用</strong>。当一个socket关闭的时候，是通过两端互发信息的四次握手过程完成的，当一端调用close()时，就说明本端没有数据再要发送了。这好似看来在握手完成以后，socket就都应该处于关闭CLOSED状态了。但这有两个问题：<br>　　第一：我们没有任何机制保证最后的一个ACK能够正常送达<br>　　第二：网络上仍然有可能有残余的数据包(wandering duplicates，或老的重复数据包)，我们也必须能够正常处理。<br>　　假设最后一个ACK丢失了，服务器会重发它发送的最后一个FIN，所以客户端必须维持一个状态信息，以便能够重发ACK；如果不维持这种状态，客户端在接收到FIN后将会响应一个RST，服务器端接收到RST后会认为这是一个错误。如果TCP协议能够正常完成必要的操作而终止双方的数据流传输，就必须完全正确的传输四次握手的四个节，不能有任何的丢失。这就是为什么<strong>socket在关闭后，仍然处于 TIME_WAIT状态，因为他要等待以便重发ACK</strong>。<br>　　如果目前连接的通信双方都已经调用了close()，假定双方都到达CLOSED状态，而没有TIME_WAIT状态时，就会出现如下的情况。现在有一个新的连接被建立起来，使用的IP地址与端口与先前的完全相同，后建立的连接又称作是原先连接的一个化身。还假定原先的连接中有数据报残存于网络之中，这样<strong>新的连接收到的数据报中有可能是先前连接的数据报</strong>。为了防止这一点，TCP不允许从处于TIME_WAIT状态的socket建立一个连接。处于TIME_WAIT状态的socket在等待两倍的MSL时间以后（<strong>之所以是两倍的MSL，Max Segment Lifetime，是由于MSL是一个数据报在网络中单向发出到认定丢失的时间，一个数据报有可能在发送途中或是其响应过程中成为残余数据报，确认一个数据报及其响应的丢弃的需要两倍的MSL</strong>），将会转变为CLOSED状态。这就意味着，一个成功建立的连接，必然使得先前网络中残余的数据报都丢失了。<br>　　由于TIME_WAIT状态所带来的相关问题，我们可以通过设置<strong>SO_LINGER</strong>标志来避免socket进入TIME_WAIT状态，这可以通过发送RST而取代正常的TCP四次握手的终止方式。但这并不是一个很好的主意，TIME_WAIT对于我们来说往往是有利的。<br>　　值得一说的是，<strong>对于基于TCP的HTTP协议，关闭TCP连接的是Server端</strong>，这样，Server端会进入TIME_WAIT状态，可想而知，对于访问量大的Web Server，会存在大量的TIME_WAIT状态，假如server一秒钟接收1000个请求，那么就会积压240*1000=240，000个TIME_WAIT的记录，维护这些状态给Server带来负担。当然现代操作系统都会用快速的查找算法来管理这些TIME_WAIT，所以对于新的TCP连接请求，判断是否hit中一个TIME_WAIT不会太费时间，但是有这么多状态要维护总是不好。<br>　　对于一个处理大量短连接的服务器（如nginx代理），如果是由服务器主动关闭客户端的连接，将导致服务器端存在大量的处于TIME_WAIT状态的socket，甚至比处于Established状态下的socket多的多，这不但发生在代理服务器上，而且也会使后端的app服务器上有大量的TIME_WAIT。这样严重影响服务器的处理能力，甚至耗尽可用的socket，停止服务。 　　TIME_WAIT是TCP协议用以保证被重新分配的socket不会受到之前残留的延迟重发报文影响的机制，是必要的逻辑保证。目前看来最好的办法是让每个TIME_WAIT早点过期。在linux上可以这么配置：<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#让TIME_WAIT状态可以重用，这样即使TIME_WAIT占满了所有端口，也不会拒绝新的请求造成障碍</span></span><br><span class="line"><span class="built_in">echo</span> <span class="string">"1"</span> &gt; /proc/sys/net/ipv4/tcp_tw_reuse</span><br><span class="line"><span class="comment">#让TIME_WAIT尽快回收，我也不知是多久，观察大概是一秒钟</span></span><br><span class="line"><span class="built_in">echo</span> <span class="string">"1"</span> &gt; /proc/sys/net/ipv4/tcp_tw_recycle</span><br></pre></td></tr></table></figure>
</li>
</ul>
<p>　　很多文档都会建议两个参数都配置上，但是我发现只用修改tcp_tw_recycle就可以解决问题的了，TIME_WAIT重用TCP协议本身就是不建议打开的。不能重用端口可能会造成系统的某些服务无法启动，比如要重启一个系统监控的软件，它用了40000端口，而这个端口在软件重启过程中刚好被使用了，就可能会重启失败的。linux默认考虑到了这个问题，有这么个设定：<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#查看系统本地可用端口极限值</span></span><br><span class="line">cat /proc/sys/net/ipv4/ip_<span class="built_in">local</span>_port_range</span><br></pre></td></tr></table></figure></p>
<p>　　用这条命令会返回两个数字，默认是：32768 61000，说明这台机器本地能向外连接61000-32768=28232个连接，注意是本地向外连接，不是这台机器的所有连接，不会影响这台机器的 80端口的对外连接数。但这个数字会影响到代理服务器（nginx）对app服务器的最大连接数，因为nginx对app是用的异步传输，所以这个环节的 连接速度很快，所以堆积的连接就很少。假如nginx对app服务器之间的带宽出了问题或是app服务器有问题，那么可能使连接堆积起来，这时可以通过设 定nginx的代理超时时间，来使连接尽快释放掉，一般来说极少能用到28232个连接。<br>　　因为有软件使用了40000端口监听，常常出错的话，可以通过设定ip_local_port_range的最小值来解决：<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">echo</span> <span class="string">"40001 61000"</span> &gt; /proc/sys/net/ipv4/ip_<span class="built_in">local</span>_port_range</span><br></pre></td></tr></table></figure></p>
<p>　　但是这么做很显然把系统可用端口数减少了，这时可以把ip_local_port_range的最大值往上调，但是好习惯是使用不超过32768的端口来侦听服务，另外也不必要去修改ip_local_port_range数值成1024 65535之类的，意义不大。</p>
<p>　　发现系统存在大量TIME_WAIT状态的连接，通过调整内核参数解决：vi /etc/sysctl.conf</p>
<p>编辑文件，加入以下内容：<br>net.ipv4.tcp_syncookies = 1 #表示开启SYN Cookies。当出现SYN等待队列溢出时，启用cookies来处理，可防范少量SYN攻击，默认为0，表示关闭；<br>net.ipv4.tcp_tw_reuse = 1 #表示开启重用。允许将TIME-WAIT sockets重新用于新的TCP连接，默认为0，表示关闭；<br>net.ipv4.tcp_tw_recycle = 1 #表示开启TCP连接中TIME-WAIT sockets的快速回收，默认为0，表示关闭。<br>net.ipv4.tcp_fin_timeout = 30  #修改系統默认的 TIMEOUT 时间</p>
<p>然后执行 /sbin/sysctl -p 让参数生效。</p>
<h2 id="u6B7B_u94FE_u63A5"><a href="#u6B7B_u94FE_u63A5" class="headerlink" title="死链接"></a>死链接</h2><p>　　问题是这样出现的，客户端正在向服务端请求数据的时候，突然拔掉客户端的网线。此时客户端死等，服务端socket一直存在。<br>　　解决该问题，需要设置KEEPALIVE属性。我们在客户端和服务端都设置KEEPALIVE属性。这样客户端没有问题了，可以主动关闭，但是服务端还是在死等，也就是说keepalive没起作用。此时需要使用TCP KEEP-ALIVE与TCP_USER_TIMEOUT机制判断通信对端是否存活。<br>　　在对端的网线被拔（手机设置为飞行模式）、网卡被卸载或者禁用的时候，对端没有机会向本地操作系统发送TCP RST或者FIN包来关闭连接。这时候操作系统不会认为对端已经挂了。所以在调用send函数的时候，返回的仍然是我们指定发送的数据字节数。当我们无法通过send的返回值来判断对端是否存活的情况下，就要使用TCP Keep-alive机制了。<br>　　在《Unix网络编程（卷一）》中提到，使用SO_KEEPALIVE套接字选项启用对套接字的保活（Keep-alive）机制。<br>　　给一个TCP套接口设置保持存活（keepalive）选项后，如果在2小时内在此套接口的任一方向都没有数据交换，TCP就自动给对方发一个保持存活探测分节（keepalive probe）。TCP提供了这种机制帮我们判断对端是否存活，如果对端没有对KeepAlive包进行正常的响应，则会导致下一次对套接字的send或者recv出错。应用程序就可以检测到这个异常。<br>　　如果发送方发送的数据包没有收到接收方回复的ACK数据包，则TCP Keep-alive机制就不会被启动，而TCP会启动超时重传机制，这样就使得TCP Keep-alive机制在未收到ACK包时失效。<br>　　在实际的即时通信开发中，都是通过心跳机制来检测死链接的</p>
<h2 id="SO_LINGER"><a href="#SO_LINGER" class="headerlink" title="SO_LINGER"></a>SO_LINGER</h2><p>　　在java中，可以给socket设置参数SO_LINGER，它决定了是否要立即释放随机分配的端口，默认不会立即释放端口，需要等待1~4分钟，连接一直处于TIME_WAIT状态，如果设置为0，当关闭连接时，就会立即释放端口。</p>
<h2 id="u5E38_u7528_u547D_u4EE4"><a href="#u5E38_u7528_u547D_u4EE4" class="headerlink" title="常用命令"></a>常用命令</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#查看系统中所有tcp连接不同连接状态的总数</span></span><br><span class="line">netstat -n | awk <span class="string">'/^tcp/ &#123;++S[$NF]&#125; END &#123;for(a in S) print a, S[a]&#125;'</span> </span><br><span class="line"><span class="comment">#查看所有的tcp连接</span></span><br><span class="line">netstat -an | grep tcp</span><br><span class="line"><span class="comment">#dump the traffic on a network，根据使用者的定义对网络上的数据包进行截获的包分析工具。 </span></span><br><span class="line"><span class="comment">#tcpdump可以将网络中传送的数据包的“头”完全截获下来提供分析。</span></span><br><span class="line"><span class="comment">#它支持针对网络层、协议、主机、网络或端口的过滤，并提供and、or、not等逻辑语句来帮助你去掉无用的信息。</span></span><br><span class="line">tcpdump</span><br></pre></td></tr></table></figure>
<h2 id="u53C2_u8003_u8D44_u6599"><a href="#u53C2_u8003_u8D44_u6599" class="headerlink" title="参考资料"></a>参考资料</h2><p><a href="http://blog.csdn.net/mei922/article/details/4801858" target="_blank" rel="external">http://blog.csdn.net/mei922/article/details/4801858</a><br><a href="http://blog.chinaunix.net/uid-20384806-id-1954363.html" target="_blank" rel="external">http://blog.chinaunix.net/uid-20384806-id-1954363.html</a><br><a href="http://blog.itechol.com/space-33-do-blog-id-6563.html" target="_blank" rel="external">http://blog.itechol.com/space-33-do-blog-id-6563.html</a><br><a href="http://qa.blog.163.com/blog/static/190147002201342115957410/" target="_blank" rel="external">http://qa.blog.163.com/blog/static/190147002201342115957410/</a><br><a href="http://qa.blog.163.com/blog/static/19014700220134132571261/?latestBlog" target="_blank" rel="external">http://qa.blog.163.com/blog/static/19014700220134132571261/?latestBlog</a><br><a href="http://www.tuicool.com/articles/zmiEZf" target="_blank" rel="external">http://www.tuicool.com/articles/zmiEZf</a></p>

      
    </div>
    <footer class="article-footer">
      <a data-url="http://yoursite.com/2015/12/01/linux/2.Linux系列之tcp/" data-id="cijzzpvcr00bq1cfsqpohgso4" class="article-share-link">Share</a>
      
      
  <ul class="article-tag-list"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/linux/">linux</a></li></ul>

    </footer>
  </div>
  
</article>


  
    <article id="post-rpc/2.RPC系列之Hessian源码分析" class="article article-type-post" itemscope itemprop="blogPost">
  <div class="article-meta">
    <a href="/2015/12/01/rpc/2.RPC系列之Hessian源码分析/" class="article-date">
  <time datetime="2015-11-30T18:00:00.000Z" itemprop="datePublished">2015-12-01</time>
</a>
    
  <div class="article-category">
    <a class="article-category-link" href="/categories/rpc/">rpc</a>
  </div>

  </div>
  <div class="article-inner">
    
    
      <header class="article-header">
        
  
    <h1 itemprop="name">
      <a class="article-title" href="/2015/12/01/rpc/2.RPC系列之Hessian源码分析/">RPC系列二之Hessian源码分析</a>
    </h1>
  

      </header>
    
    <div class="article-entry" itemprop="articleBody">
      
        <h2 id="u7B80_u4ECB"><a href="#u7B80_u4ECB" class="headerlink" title="简介"></a>简介</h2><p>　　hessian是一个采用二进制格式传输的服务框架，相对传统soap web service，更轻量，更快速。下面先通过一个简单的示例让大家对hessian有一个简单的认识，之后深入源码分析其实现机制。在下一篇博客中我们将介绍与spring的集成与原理！</p>
<h2 id="u5B9E_u73B0"><a href="#u5B9E_u73B0" class="headerlink" title="实现"></a>实现</h2><p>　　建立一个maven工程，向pom.xml中添加如下信息：<br><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="title">dependencies</span>&gt;</span></span><br><span class="line">    <span class="comment">&lt;!--&lt;dependency&gt;</span><br><span class="line">        &lt;groupId&gt;com.caucho&lt;/groupId&gt;</span><br><span class="line">        &lt;artifactId&gt;hessian&lt;/artifactId&gt;</span><br><span class="line">        &lt;version&gt;3.0.8&lt;/version&gt;</span><br><span class="line">    &lt;/dependency&gt;--&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="title">dependency</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="title">groupId</span>&gt;</span>com.caucho<span class="tag">&lt;/<span class="title">groupId</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="title">artifactId</span>&gt;</span>hessian<span class="tag">&lt;/<span class="title">artifactId</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="title">version</span>&gt;</span>2.1.12<span class="tag">&lt;/<span class="title">version</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="title">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="title">dependency</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="title">groupId</span>&gt;</span>javax.servlet<span class="tag">&lt;/<span class="title">groupId</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="title">artifactId</span>&gt;</span>servlet-api<span class="tag">&lt;/<span class="title">artifactId</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="title">version</span>&gt;</span>2.5<span class="tag">&lt;/<span class="title">version</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="title">scope</span>&gt;</span>provided<span class="tag">&lt;/<span class="title">scope</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="title">dependency</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="title">dependencies</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="title">build</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="title">pluginManagement</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="title">plugins</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="title">plugin</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="title">groupId</span>&gt;</span>org.apache.maven.plugins<span class="tag">&lt;/<span class="title">groupId</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="title">artifactId</span>&gt;</span>maven-compiler-plugin<span class="tag">&lt;/<span class="title">artifactId</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="title">version</span>&gt;</span>3.1<span class="tag">&lt;/<span class="title">version</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="title">configuration</span>&gt;</span></span><br><span class="line">                    <span class="tag">&lt;<span class="title">source</span>&gt;</span>1.6<span class="tag">&lt;/<span class="title">source</span>&gt;</span></span><br><span class="line">                    <span class="tag">&lt;<span class="title">target</span>&gt;</span>1.6<span class="tag">&lt;/<span class="title">target</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;/<span class="title">configuration</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;/<span class="title">plugin</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="title">plugins</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="title">pluginManagement</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="title">plugins</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="title">plugin</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="title">groupId</span>&gt;</span>org.apache.tomcat.maven<span class="tag">&lt;/<span class="title">groupId</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="title">artifactId</span>&gt;</span>tomcat6-maven-plugin<span class="tag">&lt;/<span class="title">artifactId</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="title">version</span>&gt;</span>2.0<span class="tag">&lt;/<span class="title">version</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="title">plugin</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="title">plugin</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="title">groupId</span>&gt;</span>org.apache.maven.plugins<span class="tag">&lt;/<span class="title">groupId</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="title">artifactId</span>&gt;</span>maven-war-plugin<span class="tag">&lt;/<span class="title">artifactId</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="title">version</span>&gt;</span>2.5<span class="tag">&lt;/<span class="title">version</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="title">plugin</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="title">plugins</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="title">build</span>&gt;</span></span><br></pre></td></tr></table></figure></p>
<p>　　接着定义一个服务接口和实现类，如下所示：<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">interface</span> <span class="title">MyService</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> String <span class="title">doSomething</span><span class="params">(String str)</span></span>;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">MySeriviceImpl</span> <span class="keyword">implements</span> <span class="title">MyService</span> </span>&#123;</span><br><span class="line">    <span class="annotation">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> String <span class="title">doSomething</span><span class="params">(String str)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="string">"hello "</span> + str;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>　　在web.xml中添加如下内容：<br><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="title">servlet</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="title">servlet-name</span>&gt;</span>myservice<span class="tag">&lt;/<span class="title">servlet-name</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="title">servlet-class</span>&gt;</span>com.caucho.hessian.server.HessianServlet<span class="tag">&lt;/<span class="title">servlet-class</span>&gt;</span></span><br><span class="line"></span><br><span class="line">    <span class="tag">&lt;<span class="title">init-param</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="title">param-name</span>&gt;</span>service-class<span class="tag">&lt;/<span class="title">param-name</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="title">param-value</span>&gt;</span>com.shihc.hessian.MySeriviceImpl<span class="tag">&lt;/<span class="title">param-value</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="title">init-param</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="title">load-on-startup</span>&gt;</span>1<span class="tag">&lt;/<span class="title">load-on-startup</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;/<span class="title">servlet</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="title">servlet-mapping</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="title">servlet-name</span>&gt;</span>myservice<span class="tag">&lt;/<span class="title">servlet-name</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="title">url-pattern</span>&gt;</span>/myservice<span class="tag">&lt;/<span class="title">url-pattern</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="title">servlet-mapping</span>&gt;</span></span><br></pre></td></tr></table></figure></p>
<p>　　运行该web程序。下面提供客户端调用代码：<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Client</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> Exception </span>&#123;</span><br><span class="line">        HessianProxyFactory proxyFactory = <span class="keyword">new</span> HessianProxyFactory();;</span><br><span class="line">        MyService service = (MyService)proxyFactory.create(MyService.class,</span><br><span class="line">                <span class="string">"http://localhost:8080/hessian-demo/myservice"</span>);</span><br><span class="line"></span><br><span class="line">        System.out.println(service.doSomething(<span class="string">"xixixixi"</span>));</span><br><span class="line">        System.out.println(<span class="string">"ok!"</span>);;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<h2 id="u670D_u52A1_u7AEF_u5B9E_u73B0_u673A_u5236"><a href="#u670D_u52A1_u7AEF_u5B9E_u73B0_u673A_u5236" class="headerlink" title="服务端实现机制"></a>服务端实现机制</h2><p>　　从上面的代码可以看出，在服务端的实现中，最重要的便是在web.xml中配置了一个HessianServlet。下面列出该类的关键代码，注意代码中的注释<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">init</span><span class="params">(ServletConfig config)</span> <span class="keyword">throws</span> ServletException </span>&#123;</span><br><span class="line">    <span class="comment">//获取servlet中配置的参数service-class</span></span><br><span class="line">    String className = <span class="keyword">this</span>.getInitParameter(<span class="string">"service-class"</span>);</span><br><span class="line">    <span class="comment">//加载该类</span></span><br><span class="line">    ClassLoader e = Thread.currentThread().getContextClassLoader();</span><br><span class="line">    <span class="keyword">if</span>(e != <span class="keyword">null</span>) &#123;</span><br><span class="line">        <span class="keyword">this</span>._serviceClass = Class.forName(className, <span class="keyword">false</span>, e);</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        <span class="keyword">this</span>._serviceClass = Class.forName(className);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">//初始化该类</span></span><br><span class="line">    <span class="keyword">this</span>._service = <span class="keyword">this</span>._serviceClass.newInstance();</span><br><span class="line">    ......</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">service</span><span class="params">(ServletRequest request, ServletResponse response)</span> <span class="keyword">throws</span> IOException, ServletException </span>&#123;</span><br><span class="line">    HttpServletRequest req = (HttpServletRequest)request;</span><br><span class="line">    HttpServletResponse res = (HttpServletResponse)response;</span><br><span class="line">    <span class="comment">//如果为get方法，则提示Hessian只支持post模式的请求方式</span></span><br><span class="line">    <span class="keyword">if</span>(!req.getMethod().equals(<span class="string">"POST"</span>)) &#123;</span><br><span class="line">        res.setStatus(<span class="number">500</span>, <span class="string">"Hessian Requires POST"</span>);</span><br><span class="line">        PrintWriter out2 = res.getWriter();</span><br><span class="line">        res.setContentType(<span class="string">"text/html"</span>);</span><br><span class="line">        out2.println(<span class="string">"&lt;h1&gt;Hessian Requires POST&lt;/h1&gt;"</span>);</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        Object out = <span class="keyword">this</span>._service;</span><br><span class="line">        <span class="comment">//因为使用了成员变量_skeleton，此处采用同步的代码</span></span><br><span class="line">        <span class="keyword">synchronized</span>(<span class="keyword">this</span>._service) &#123;</span><br><span class="line">            <span class="keyword">if</span>(<span class="keyword">this</span>._skeleton == <span class="keyword">null</span>) &#123;</span><br><span class="line">                <span class="keyword">this</span>._skeleton = <span class="keyword">new</span> HessianSkeleton(<span class="keyword">this</span>._service);</span><br><span class="line">            &#125;</span><br><span class="line"></span><br><span class="line">            String serviceId = req.getPathInfo();</span><br><span class="line">            String objectId = request.getParameter(<span class="string">"ejbid"</span>);</span><br><span class="line">            <span class="keyword">if</span>(<span class="keyword">this</span>._service <span class="keyword">instanceof</span> Service) &#123;</span><br><span class="line">                ((Service)<span class="keyword">this</span>._service).setRequestObject(request, serviceId, objectId);</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="comment">//包装输入输出流</span></span><br><span class="line">            ServletInputStream is = request.getInputStream();</span><br><span class="line">            ServletOutputStream os = response.getOutputStream();</span><br><span class="line">            HessianInput in = <span class="keyword">new</span> HessianInput(is);</span><br><span class="line">            HessianOutput out1 = <span class="keyword">new</span> HessianOutput(os);</span><br><span class="line"></span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                <span class="comment">//调用执行，在invoke中返回结果</span></span><br><span class="line">                <span class="keyword">this</span>._skeleton.invoke(in, out1);</span><br><span class="line">            &#125; <span class="keyword">catch</span> (Throwable var14) &#123;</span><br><span class="line">                <span class="keyword">throw</span> <span class="keyword">new</span> ServletException(var14);</span><br><span class="line">            &#125;</span><br><span class="line"></span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>　　从上面的代码可以看出，HessianServlet主要完成了服务类的初始化工作。同时在每次请求到达时，都是通过HessianSkeleton进行请求的处理和响应，下面我们开始分析HessianSkeleton。</p>
<h2 id="HessianSkeleton"><a href="#HessianSkeleton" class="headerlink" title="HessianSkeleton"></a>HessianSkeleton</h2><p>　　在HessianSekleton中主要完成了请求数据和相应数据的编解码工作，并通过反射的方式调用服务类！下面我们看看HessianSkeleton构造方法<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="title">HessianSkeleton</span><span class="params">(Object service)</span> </span>&#123;</span><br><span class="line">    <span class="keyword">this</span>._service = service;</span><br><span class="line">    Method[] methodList = service.getClass().getMethods();</span><br><span class="line"></span><br><span class="line">    <span class="keyword">for</span>(<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; methodList.length; ++i) &#123;</span><br><span class="line">        Method method = methodList[i];</span><br><span class="line">        <span class="keyword">if</span>(<span class="keyword">this</span>._methodMap.get(method.getName()) == <span class="keyword">null</span>) &#123;</span><br><span class="line">            <span class="keyword">this</span>._methodMap.put(method.getName(), methodList[i]);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        Class[] param = method.getParameterTypes();</span><br><span class="line">        String mangledName = method.getName() + <span class="string">"__"</span> + param.length;</span><br><span class="line">        <span class="keyword">this</span>._methodMap.put(mangledName, methodList[i]);</span><br><span class="line">        <span class="keyword">this</span>._methodMap.put(<span class="keyword">this</span>.mangleName(method, <span class="keyword">false</span>), methodList[i]);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>　　在hessian的构造方法中，我们完成了服务类方法的解析，并通过Map保存在_methodMap中，注意，此处考虑了重载方法的实现。另一个重要的方法就是invoke，该方法借助于HessianInput和HessianOutput完成了协议的编解码工作，可以理解为一个静态代理模式。<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">invoke</span><span class="params">(HessianInput in, HessianOutput out)</span> <span class="keyword">throws</span> Throwable </span>&#123;</span><br><span class="line">    <span class="comment">//请求数据开始解析</span></span><br><span class="line">    in.startCall();</span><br><span class="line">    Method method = (Method)<span class="keyword">this</span>._methodMap.get(in.getMethod());</span><br><span class="line">    <span class="keyword">if</span>(method == <span class="keyword">null</span>) &#123;</span><br><span class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> IOException(<span class="string">"No server method matching:"</span> + in.getMethod());</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        Class[] args = method.getParameterTypes();</span><br><span class="line">        Object[] values = <span class="keyword">new</span> Object[args.length];</span><br><span class="line"></span><br><span class="line">        <span class="keyword">for</span>(<span class="keyword">int</span> result = <span class="number">0</span>; result &lt; args.length; ++result) &#123;</span><br><span class="line">            values[result] = in.readObject(args[result]);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">//请求数据完成解析</span></span><br><span class="line">        in.completeCall();</span><br><span class="line">        Object var9 = <span class="keyword">null</span>;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            var9 = method.invoke(<span class="keyword">this</span>._service, values);</span><br><span class="line">        &#125; <span class="keyword">catch</span> (Throwable var8) &#123;</span><br><span class="line">            Throwable e = var8;</span><br><span class="line">            <span class="keyword">if</span>(var8 <span class="keyword">instanceof</span> InvocationTargetException) &#123;</span><br><span class="line">                e = ((InvocationTargetException)var8).getTargetException();</span><br><span class="line">            &#125;</span><br><span class="line"></span><br><span class="line">            out.startReply();</span><br><span class="line">            out.writeFault(<span class="string">"ServiceException"</span>, e.getMessage(), e);</span><br><span class="line">            out.completeReply();</span><br><span class="line">            <span class="keyword">return</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">//请求数据开始写入</span></span><br><span class="line">        out.startReply();</span><br><span class="line">        out.writeObject(var9);</span><br><span class="line">        out.completeReply();</span><br><span class="line">        <span class="comment">//请求数据结束写入</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>　　可以看到，整个解析过程非常的简单。首先反序列化请求参数，在通过反射执行服务类，最后序列化响应结果并返回，仅此而已。</p>
<h2 id="u5BA2_u6237_u7AEF_u5B9E_u73B0_u673A_u5236"><a href="#u5BA2_u6237_u7AEF_u5B9E_u73B0_u673A_u5236" class="headerlink" title="客户端实现机制"></a>客户端实现机制</h2><p>　　客户端的代码很简单，主要涉及两个类：HessianProxyFactory和HessianProxy，其中HessianProxy继承自InvocationHandler，熟悉jdk动态代理的同学应该很熟悉。这里就不再详细介绍了。
　　</p>
<h2 id="u5E8F_u5217_u5316"><a href="#u5E8F_u5217_u5316" class="headerlink" title="序列化"></a>序列化</h2><p>　　无论是服务端还是客户端，都需要用到HessianOutput和HessianInput，它们才是真正进行序列化的工具。同时在com.caucho.hessian.io包中还提供了各种序列化与反序列工具。相比于jdk提供的序列化，hessian的序列化在数据量大小上无疑有着极大的优势。hessian的二进制协议主要分为三个部分：<br>　　1. 消息头：标识消息的开始。在tcp中，通常为了防止粘包现象，可以在消息头中存入消息的长度以保证正常的解析，也可以作为magic头，一定程度上保证消息的安全性。但是现在hessian提供的rpc是通过http完成的，貌似此时用处不大。<br>　　2. 消息体：如果为请求消息，则要是保存的是方法名和参数等信息。如果是响应消息，则通过com.caucho.hessian.io包中提供的序列化工具进行序列化写入。<br>　　3. 消息尾：标识消息的结束</p>
<h2 id="u603B_u7ED3"><a href="#u603B_u7ED3" class="headerlink" title="总结"></a>总结</h2><p>　　我们可以看出，采用hessian进行rpc调用是非常方便的，因为它已经帮我们实现好了消息的编解码和动态代理两个最核心的功能。同时它采用自定义的协议，在数据量大小上，相比于jdk的序列化机制，也是有非常大的优势的。不过，由于其只提供了http的访问方式，在高并发下存在一定的性能问题。参考代码：<a href="/code/hessian-demo.zip">hessian-demo.zip</a><br>　　在hessian的源码中，我们还可以看到包com.caucho.burlap的存在。与hessian基于二进制协议不同，它是基于xml协议的，这里不再赘述！这里我们主要使用了java版的hessian，实际上它还提供了.net、erlang、c等的实现。</p>
<h2 id="u53C2_u8003_u8D44_u6599"><a href="#u53C2_u8003_u8D44_u6599" class="headerlink" title="参考资料"></a>参考资料</h2><p><a href="http://qq85609655.iteye.com/blog/970266" target="_blank" rel="external">http://qq85609655.iteye.com/blog/970266</a><br><a href="http://hessian.caucho.com/" target="_blank" rel="external">http://hessian.caucho.com/</a></p>

      
    </div>
    <footer class="article-footer">
      <a data-url="http://yoursite.com/2015/12/01/rpc/2.RPC系列之Hessian源码分析/" data-id="cijzzpv3q002q1cfswo11pf9x" class="article-share-link">Share</a>
      
      
  <ul class="article-tag-list"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/hessisan/">hessisan</a></li><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/java/">java</a></li><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/rpc/">rpc</a></li></ul>

    </footer>
  </div>
  
</article>


  
    <article id="post-linux/1.Linux系列之常用命令" class="article article-type-post" itemscope itemprop="blogPost">
  <div class="article-meta">
    <a href="/2015/12/01/linux/1.Linux系列之常用命令/" class="article-date">
  <time datetime="2015-11-30T17:00:00.000Z" itemprop="datePublished">2015-12-01</time>
</a>
    
  <div class="article-category">
    <a class="article-category-link" href="/categories/linux/">linux</a>
  </div>

  </div>
  <div class="article-inner">
    
    
      <header class="article-header">
        
  
    <h1 itemprop="name">
      <a class="article-title" href="/2015/12/01/linux/1.Linux系列之常用命令/">Linux系列一之常用命令</a>
    </h1>
  

      </header>
    
    <div class="article-entry" itemprop="articleBody">
      
        <h2 id="u6587_u4EF6_u89E3_u538B_u7F29"><a href="#u6587_u4EF6_u89E3_u538B_u7F29" class="headerlink" title="文件解压缩"></a>文件解压缩</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#解压*.tar.gz</span></span><br><span class="line">tar -zxvf *.tar.gz</span><br><span class="line"><span class="comment">#解压*.tgz</span></span><br><span class="line">tar -zxvf kafka_2.<span class="number">9.2</span>-<span class="number">0.8</span>.<span class="number">2.1</span>.tgz</span><br><span class="line"><span class="comment">#解压*.zip</span></span><br><span class="line">unzip mysql-<span class="number">5.6</span>.<span class="number">24</span></span><br></pre></td></tr></table></figure>
<h2 id="u521B_u5EFA_u6587_u4EF6"><a href="#u521B_u5EFA_u6587_u4EF6" class="headerlink" title="创建文件"></a>创建文件</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">touch xx.data</span><br></pre></td></tr></table></figure>
<h2 id="u6587_u4EF6_u6743_u9650"><a href="#u6587_u4EF6_u6743_u9650" class="headerlink" title="文件权限"></a>文件权限</h2><p>　　命令格式为：chmod [who] operator [permission] filename<br>who的含义有：u 文件属主权限、g 同组用户权限、o其他用户权限、a 所有用户<br>operator的含义有：+ 增加权限、- 取消权限、= 设定权限<br>permission的含义有：r 读权限、w 写权限、x 执行权限<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#收回所有用户的执行权限</span></span><br><span class="line">chmod a-x myfile</span><br><span class="line"><span class="comment">#收回同组用户和其他用户的写权限</span></span><br><span class="line">chmod og-w myfile</span><br><span class="line"><span class="comment">#赋予同组用户写权限</span></span><br><span class="line">chmod g+w myfile</span><br><span class="line"><span class="comment">#赋予文件属主执行权限</span></span><br><span class="line">chmod u+x myfile</span><br><span class="line">本用户执行那个权限，其他用户不可写</span><br><span class="line">chomd u+x o-w myfile </span><br><span class="line"></span><br><span class="line"><span class="comment">#注意：r=4  w=2 x=1</span></span><br><span class="line"><span class="comment">#赋予所有用户读、写和执行权限</span></span><br><span class="line">chmod <span class="number">666</span> myfile</span><br><span class="line"><span class="comment">#赋予文件属主读、写和执行的权限，其他用户读的权限</span></span><br><span class="line">chmod <span class="number">744</span> myfile</span><br><span class="line"><span class="comment">#赋予文件属主读、写和执行的权限</span></span><br><span class="line">chmod <span class="number">700</span> myfile</span><br><span class="line"><span class="comment">#一次设置目录下所有文件</span></span><br><span class="line">chmod <span class="number">755</span> * </span><br><span class="line"><span class="comment">#连同子目录下的文件一起设置</span></span><br><span class="line">chmod -R <span class="number">664</span> </span><br><span class="line"></span><br><span class="line"><span class="comment">#目录的权限 </span></span><br><span class="line"><span class="comment">#读：列出其中的内容。 写：在目录中创建文件。 执行：可以搜索和访问该目录</span></span><br><span class="line"><span class="comment">#注意：目录的权限会覆盖目录中文件的选线</span></span><br></pre></td></tr></table></figure></p>
<h2 id="u7B26_u53F7_u8FDE_u63A5"><a href="#u7B26_u53F7_u8FDE_u63A5" class="headerlink" title="符号连接"></a>符号连接</h2><p>　　符号链接分为软连接和硬链接。软连接类似于windows下的快捷方式。创建命令为 ln<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">touch linkTest</span><br><span class="line"><span class="comment">#创建文件linkTest的快捷方式，保存到/user/linkfile</span></span><br><span class="line">ln <span class="operator">-s</span> linkTest /user/linkfile</span><br></pre></td></tr></table></figure></p>
<h2 id="u6587_u4EF6_u64CD_u4F5C"><a href="#u6587_u4EF6_u64CD_u4F5C" class="headerlink" title="文件操作"></a>文件操作</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#cat完整的显示一个文件，如果需要每次显示一页，</span></span><br><span class="line"><span class="comment">#可以使用more或者把cat命令的输出通过管道传递到另外一个具有分页功能的命令中</span></span><br><span class="line">cat myfile | more</span><br><span class="line"><span class="comment">#将文件myfile1和myfile2文件合并成文件bigfie</span></span><br><span class="line">cat myfile1 myfile2 &gt; bigfile</span><br><span class="line"><span class="comment">#创建一个新文件，并向其中输入一些内容，可以使用cat命令，将标准输出重定向到到新文件</span></span><br><span class="line"><span class="comment">#按CTRL-D结束</span></span><br><span class="line">cat &gt; catfile</span><br></pre></td></tr></table></figure>
<h2 id="crontab"><a href="#crontab" class="headerlink" title="crontab"></a>crontab</h2><p>　　命令形式；crontab [-u user] -e -l -r<br>　　-e编辑crontab文件  -l列出crontab文件中的内容  -r删除crontab文件<br>　　crontab格式：分 时 日 月 星期 要运行的命令。各域中，横杠-表示一个时间范围，逗号表示哪几个时间点，*表示连续的时间段。shell脚本需为绝对路径<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#每晚的21:30运行/apps/bin目录下的cleanup.sh</span></span><br><span class="line"><span class="number">30</span> <span class="number">21</span> * * *  /apps/bin/cleanup.sh</span><br><span class="line"></span><br><span class="line"><span class="comment">#每月1、10、22日的4:45运行/apps/bin目录下的backup.sh</span></span><br><span class="line"><span class="number">45</span> <span class="number">4</span> <span class="number">1</span>,<span class="number">10</span>,<span class="number">22</span> * * /apps/bin/backup.sh</span><br><span class="line"></span><br><span class="line"><span class="comment">#每周六、日的1:10运行一个find命令</span></span><br><span class="line"><span class="number">10</span> <span class="number">1</span> * * <span class="number">6</span>,<span class="number">0</span> find -name <span class="string">"core"</span> -exec rm &#123;&#125; \;</span><br><span class="line"></span><br><span class="line"><span class="comment">#每天18:00至23:00之间每隔30分钟运行/apps/bin目录下的dbcheck.sh</span></span><br><span class="line"><span class="number">0</span>,<span class="number">30</span> <span class="number">18</span>-<span class="number">23</span> * * /apps/bin/dbcheck.sh</span><br><span class="line"></span><br><span class="line"><span class="comment">#在/home/local/test中新建文件testcron，输入</span></span><br><span class="line"><span class="number">0</span>,<span class="number">15</span>,<span class="number">30</span>,<span class="number">45</span> * * * * /bin/<span class="built_in">echo</span> `date` &gt; /dev/console</span><br><span class="line"><span class="comment">#提交任务，后提交的会覆盖之前提交的</span></span><br><span class="line">crontab testcron</span><br><span class="line"></span><br><span class="line"><span class="comment">#在/var/spool/cron中存在文件root，内容与testcron中的一致</span></span><br><span class="line"><span class="comment">#列出crontab文件列表</span></span><br><span class="line">crontab <span class="operator">-l</span></span><br><span class="line"><span class="comment">#可以使用该命令对crontab文件做一备份</span></span><br><span class="line">crontab <span class="operator">-l</span> &gt; <span class="variable">$HOME</span>/mycron <span class="comment">#mycron文件的内容极为crontab -l输出的内容</span></span><br><span class="line"><span class="comment">#编辑crontab文件</span></span><br><span class="line">crontab <span class="operator">-e</span></span><br></pre></td></tr></table></figure></p>
<p>　　at命令：向cron提交守护进程，使其在稍后的时间运行，如果时间太长，比如一个月，则建议使用crontab。<br>　　命令格式：at [-f script] [-m -l -r] [time] [date]<br>　　作业提交后会被拷贝到/var/spool/at目录中。清除一个作业：atrm [job no] 或 at -r [job no]</p>
<ol>
<li>cron：系统调度进程 crontab命令允许用户提交，编辑或删除相应的作业。每一个用户可以有一个crontab文件来保存调度信息</li>
<li>at：使用它在一个的丁的时间运行一些特殊的作业</li>
<li>&amp;：使用它在后台运行一个占用时间不长的进程</li>
<li>nohup：使用他在后台运行一个命令，即使在用户退出时也不受影响</li>
</ol>
<h2 id="umask"><a href="#umask" class="headerlink" title="umask"></a>umask</h2><p>　　设置文件创建时的缺省模式，即<strong>文件创建时不具备的权限</strong>，从下表可以看出，文件在创建时不可能拥有执行权限。使用umask命令设置文件默认的生成掩码，默认的生成掩码告诉系统创建一个文件或目录不应该赋予哪些权限。如果用户将umask命令放在环境文件.bash_profile中，就可以控制所有新建的文件和目录的访问权限。</p>
<table>
<thead>
<tr>
<th style="text-align:center">umask</th>
<th style="text-align:center">文件</th>
<th style="text-align:center">目录</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:center">0</td>
<td style="text-align:center">6</td>
<td style="text-align:center">7</td>
</tr>
<tr>
<td style="text-align:center">1</td>
<td style="text-align:center">6</td>
<td style="text-align:center">6</td>
</tr>
<tr>
<td style="text-align:center">2</td>
<td style="text-align:center">4</td>
<td style="text-align:center">5</td>
</tr>
<tr>
<td style="text-align:center">3</td>
<td style="text-align:center">4</td>
<td style="text-align:center">4</td>
</tr>
<tr>
<td style="text-align:center">4</td>
<td style="text-align:center">2</td>
<td style="text-align:center">3</td>
</tr>
<tr>
<td style="text-align:center">5</td>
<td style="text-align:center">2</td>
<td style="text-align:center">2</td>
</tr>
<tr>
<td style="text-align:center">6</td>
<td style="text-align:center">0</td>
<td style="text-align:center">1</td>
</tr>
<tr>
<td style="text-align:center">7</td>
<td style="text-align:center">0</td>
<td style="text-align:center">0</td>
</tr>
</tbody>
</table>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#表示设置不允许同组用户和其他用户有写的权限。</span></span><br><span class="line"><span class="built_in">umask</span> <span class="number">022</span></span><br><span class="line"><span class="comment">#显示当前的默认生成掩码。</span></span><br><span class="line"><span class="built_in">umask</span></span><br><span class="line"><span class="comment">#文件创建时的权限为664</span></span><br><span class="line"><span class="built_in">umask</span> <span class="number">002</span></span><br></pre></td></tr></table></figure>
<h2 id="u65E5_u671F_u67E5_u8BE2"><a href="#u65E5_u671F_u67E5_u8BE2" class="headerlink" title="日期查询"></a>日期查询</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#查看系统日期</span></span><br><span class="line">&gt; date</span><br><span class="line">Sat Mar <span class="number">22</span> <span class="number">11</span>:<span class="number">40</span>:<span class="number">49</span> CST <span class="number">2014</span></span><br></pre></td></tr></table></figure>
<h2 id="u6587_u4EF6_u67E5_u627E"><a href="#u6587_u4EF6_u67E5_u627E" class="headerlink" title="文件查找"></a>文件查找</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><span class="line">&gt; ls <span class="operator">-l</span></span><br><span class="line">total <span class="number">12</span></span><br><span class="line">drwx------. <span class="number">25</span> shihuacai shihuacai <span class="number">4096</span> Feb <span class="number">27</span> <span class="number">22</span>:<span class="number">54</span> shihuacai</span><br><span class="line">-rw-r--r--. <span class="number">1</span> root root <span class="number">4</span> Mar <span class="number">22</span> <span class="number">11</span>:<span class="number">15</span> <span class="built_in">test</span>1</span><br><span class="line">-rw-r--r--. <span class="number">1</span> root root <span class="number">8</span> Mar <span class="number">22</span> <span class="number">11</span>:<span class="number">15</span> <span class="built_in">test</span>2</span><br><span class="line"><span class="comment">#只输出了文件夹，匹配以d开始的</span></span><br><span class="line">&gt; ls <span class="operator">-l</span> | grep ^d  </span><br><span class="line">drwx------. <span class="number">25</span> shihuacai shihuacai <span class="number">4096</span> Feb <span class="number">27</span> <span class="number">22</span>:<span class="number">54</span> shihuacai</span><br><span class="line"></span><br><span class="line"><span class="comment">#在自己的根目录$HOME中查找文件名符合*.txt的文件，并打印</span></span><br><span class="line">find ~ -name <span class="string">"*.txt"</span> -print</span><br><span class="line"></span><br><span class="line"><span class="comment">#使用exec或ok来执行shell命令</span></span><br><span class="line"><span class="comment">#列出当前目录下所有匹配的文件</span></span><br><span class="line">find . -type f -exec ls <span class="operator">-l</span> &#123;&#125; \</span><br><span class="line"></span><br><span class="line"><span class="comment">#在/logs目录中查找更改时间在5日以前的文件并删除它们</span></span><br><span class="line">find logs -type f -mtime +<span class="number">5</span> -ok rm &#123;&#125; \</span><br><span class="line"><span class="comment">#-ok 以安全模式运行，即会提示是否需要删除文件</span></span><br><span class="line"></span><br><span class="line"><span class="comment">#查找系统中的每一个普通文件，然后使用xargs命令来测试他们分别属于哪类文件</span></span><br><span class="line">find / -type f -print | xargs file</span><br><span class="line"></span><br><span class="line"><span class="comment">#在/apps/audit目录下查找所有用户具有读、写和执行权限的文件，并收回相应的写权限</span></span><br><span class="line">find /apps/audit/ -perm -<span class="number">7</span> -print | xargs chmod o-w</span><br><span class="line"></span><br><span class="line"><span class="comment">#在所有的普通文件中搜索device这个词</span></span><br><span class="line">find / -type <span class="operator">-f</span> -print | xargs grep <span class="string">"device"</span></span><br><span class="line"></span><br><span class="line"><span class="comment">#在当前目录下的所有普通文件中搜索DBO这个词，\用来取消find命令中的*在shell中的特殊含义</span></span><br><span class="line">find . -name *\ -type f -print | xargs grep <span class="string">"DBO"</span></span><br></pre></td></tr></table></figure>
<h2 id="chown"><a href="#chown" class="headerlink" title="chown"></a>chown</h2><p>　　修改文件的属主，即修改属于哪个用户。只有文件的属主有权更改其他属主和所属的组<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#将文件aaa的属主变为test</span></span><br><span class="line">chown <span class="built_in">test</span> aaa</span><br><span class="line"><span class="comment">#将文件files的属主和组都改成zh888。</span></span><br><span class="line">chown zh888.zh888 files</span><br><span class="line"><span class="comment">#将files所有目录和子目录下的所有文件或目录的主和组都改成zh888.</span></span><br><span class="line">chown -R zh888.zh888 files</span><br></pre></td></tr></table></figure></p>
<h2 id="u7528_u6237_u64CD_u4F5C"><a href="#u7528_u6237_u64CD_u4F5C" class="headerlink" title="用户操作"></a>用户操作</h2><p>　　1. Linux操作系统是多用户多任务操作系统，包括用户账户和组账户两种，用户账户（普通用户账户，超级用户账户），组账户就是用户账户的集合，centos 组中有两种类型，私有组和标准组。当创建一个新用户时，若没有指定他所属的组，centos就建立一个和该用户相同的私有组，此私有组中只包括用户自己。标准组可以容纳多个用户，如果要使用标准组，那创建一个新的用户时就应该指定他所属于的组。<br>　　2. Linux环境下的账户系统文件主要在/etc/passwd, /etc/shadow, /etc/group和/etc/gshadow四个文件。基本含义就不多说了重点说一下，root的uid是0，从1-499是系统的标准账户，普通用户从uid 500开始。<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#添加一个用户zh888</span></span><br><span class="line">useradd zhh888</span><br><span class="line"><span class="comment">#新建一个blog组</span></span><br><span class="line">groupadd blog</span><br><span class="line"><span class="comment">#创建一个新用户zh，同时加入blog附加组中</span></span><br><span class="line">useradd -G blog zh</span><br><span class="line"><span class="comment">#创建一个新用户ftpadmin,指定目录是/var/ftp/pub,不创建自家目录（-M)</span></span><br><span class="line">useradd <span class="operator">-d</span> /var/ftp/pub -M ftpadmin</span><br><span class="line"><span class="comment">#删除ftpadmin用户</span></span><br><span class="line">userdel ftpadmin</span><br><span class="line"><span class="comment">#删除zh888用户并删除/home中的目录。</span></span><br><span class="line">userdel -r zhh888</span><br><span class="line"><span class="comment">#删除blog组</span></span><br><span class="line">groupdel blog</span><br><span class="line">修改已经存在的用户</span><br><span class="line">usermod </span><br><span class="line">修改已经存在的组</span><br><span class="line">groupmod</span><br></pre></td></tr></table></figure></p>
<p>　　当使用groupdel一个组的时候，如果有用户把这个组当作主组，那么删除这个组时就会出现这个报错信息。解决方法就是更换用户的主组，使用usermod -g groupname username。当没有用户把这个组当作主组的时候，使用groupdel groupname时便可以把这个组删除掉。<br>　　注意usermod -g groupname username是把username的主组变成groupname，而usermod -G groupname username只是把用户加到groupname组，并没有改变主组。</p>
<p>　　系统内有关组的信息放在/etc/group文件中，用户的信息放在/etc/passwd文件中。<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#查看名为"Plants"的组内的所有用户</span></span><br><span class="line"><span class="comment">#1. 先查询组用户</span></span><br><span class="line">grep <span class="string">'Plants'</span> /etc/group</span><br><span class="line"><span class="comment">#输出：Plants：x：1003，说明gid是1003</span></span><br><span class="line"><span class="comment">#在/etc/passwd中查找组号是1003的用户（/etc/passwd文件中第四列是gid，两列之间用 : 分开）</span></span><br><span class="line">awk -F<span class="string">":"</span> <span class="string">'&#123;print $1"\t\t"$4&#125;'</span> /etc/passwd | grep <span class="string">'1003'</span></span><br><span class="line"><span class="comment"># :表示用:作为分隔符；print 打印；$1和$4分别表示第一列和第四列，即用户名和组号；\t表示制表符；grep '1003'表示将含有1003的行取出。</span></span><br></pre></td></tr></table></figure></p>
<h2 id="awk"><a href="#awk" class="headerlink" title="awk"></a>awk</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#从一个文件中抽取第1个和第5个域，并将其输 出到一个临时文件中</span></span><br><span class="line"><span class="comment">#如果这一操作未成功，我希望能够收到一个相应邮件：</span></span><br><span class="line">awk <span class="string">'&#123;print $1,$5&#125;'</span> test.file &gt; tmp.file || <span class="built_in">echo</span> <span class="string">"failed"</span></span><br><span class="line"></span><br><span class="line"><span class="comment">#将/etc/passwd文件中的第一列内容输出到sort.out文件中</span></span><br><span class="line"><span class="comment">#重定向符号一定要离开sort两个空格（sort排序）</span></span><br><span class="line">cat passwd | awk -F: <span class="string">'&#123;print $1&#125;'</span> | sort <span class="number">1</span>&gt;sort.out</span><br></pre></td></tr></table></figure>
<h2 id="sort"><a href="#sort" class="headerlink" title="sort"></a>sort</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#对文件中的内容进行排序并输出</span></span><br><span class="line">sort &lt; <span class="built_in">test</span>1 <span class="built_in">test</span>2</span><br><span class="line"><span class="comment">#将文件test1和test2 中的内容排序后输出到test1test2sort文件中</span></span><br><span class="line">sort &lt; <span class="built_in">test</span>1 <span class="built_in">test</span>2 &gt; <span class="built_in">test</span>1<span class="built_in">test</span>2sort</span><br></pre></td></tr></table></figure>
<h2 id="vi"><a href="#vi" class="headerlink" title="vi"></a>vi</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 打开文件</span></span><br><span class="line">vi /etc/sysconfig/network</span><br><span class="line"><span class="comment"># 输入i，变成编辑状态</span></span><br><span class="line"><span class="comment"># 编辑完成后，输入esc，</span></span><br><span class="line"><span class="comment"># 保存退出，输入:wq</span></span><br><span class="line"><span class="comment"># 不保存退出，输入:q!</span></span><br></pre></td></tr></table></figure>
<h2 id="24_23__u7EDF_u8BA1_u4F20_u9012_u53C2_u6570_u7684_u4E2A_u6570"><a href="#24_23__u7EDF_u8BA1_u4F20_u9012_u53C2_u6570_u7684_u4E2A_u6570" class="headerlink" title="$# 统计传递参数的个数"></a>$# 统计传递参数的个数</h2><h2 id="u78C1_u76D8_u4FE1_u606F"><a href="#u78C1_u76D8_u4FE1_u606F" class="headerlink" title="磁盘信息"></a>磁盘信息</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#-h, --human-readable  print sizes in human readable format (e.g., 1K 234M 2G)</span></span><br><span class="line">df -h</span><br><span class="line">df -k | awk <span class="string">'&#123;print $1&#125;'</span>|grep -v <span class="string">"Filesystem"</span></span><br><span class="line"><span class="comment">#不显示/dev/部分</span></span><br><span class="line">df -k | awk <span class="string">'&#123;print $1&#125;'</span>|grep -v <span class="string">"Filesystem"</span> | sed s<span class="string">'/\/dev\///g'</span></span><br></pre></td></tr></table></figure>
<h2 id="tee"><a href="#tee" class="headerlink" title="tee"></a>tee</h2><p>　　将输出的副本输送到标准输出的同时，也拷贝到相应的文件件中<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">[root@localhost home]<span class="comment"># who | tee who.out</span></span><br><span class="line">root tty1 <span class="number">2014</span>-<span class="number">03</span>-<span class="number">22</span> <span class="number">10</span>:<span class="number">29</span> (:<span class="number">0</span>)</span><br><span class="line">root pts/<span class="number">0</span> <span class="number">2014</span>-<span class="number">03</span>-<span class="number">22</span> <span class="number">10</span>:<span class="number">50</span> (:<span class="number">0.0</span>)</span><br><span class="line">root pts/<span class="number">1</span> <span class="number">2014</span>-<span class="number">03</span>-<span class="number">22</span> <span class="number">11</span>:<span class="number">11</span> (:<span class="number">0.0</span>)</span><br><span class="line">root pts/<span class="number">2</span> <span class="number">2014</span>-<span class="number">03</span>-<span class="number">22</span> <span class="number">11</span>:<span class="number">11</span> (:<span class="number">0.0</span>)</span><br><span class="line"></span><br><span class="line">[root@localhost home]<span class="comment"># cat who.out</span></span><br><span class="line">root tty1 <span class="number">2014</span>-<span class="number">03</span>-<span class="number">22</span> <span class="number">10</span>:<span class="number">29</span> (:<span class="number">0</span>)</span><br><span class="line">root pts/<span class="number">0</span> <span class="number">2014</span>-<span class="number">03</span>-<span class="number">22</span> <span class="number">10</span>:<span class="number">50</span> (:<span class="number">0.0</span>)</span><br><span class="line">root pts/<span class="number">1</span> <span class="number">2014</span>-<span class="number">03</span>-<span class="number">22</span> <span class="number">11</span>:<span class="number">11</span> (:<span class="number">0.0</span>)</span><br><span class="line">root pts/<span class="number">2</span> <span class="number">2014</span>-<span class="number">03</span>-<span class="number">22</span> <span class="number">11</span>:<span class="number">11</span> (:<span class="number">0.0</span>)</span><br></pre></td></tr></table></figure></p>
<h2 id="u5185_u5B58_u4FE1_u606F"><a href="#u5185_u5B58_u4FE1_u606F" class="headerlink" title="内存信息"></a>内存信息</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#-b,-k,-m,-g show output in bytes, KB, MB, or GB</span></span><br><span class="line"><span class="comment">#-s update every [delay] seconds</span></span><br><span class="line">free -m <span class="operator">-s</span></span><br></pre></td></tr></table></figure>
<h2 id="u7F51_u7EDC_u4FE1_u606F"><a href="#u7F51_u7EDC_u4FE1_u606F" class="headerlink" title="网络信息"></a>网络信息</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#根据端口或pid查进程</span></span><br><span class="line">netstat -anp | grep <span class="number">9000</span></span><br><span class="line"><span class="comment">#查看指定进程被某些ip的连接数量</span></span><br><span class="line">netstat -anp | grep <span class="number">10.10</span>.*kn | wc <span class="operator">-l</span></span><br><span class="line">netstat -anp | grep kn | wc <span class="operator">-l</span></span><br><span class="line">netstat -ap | grep kn</span><br></pre></td></tr></table></figure>
<h2 id="nohup"><a href="#nohup" class="headerlink" title="nohup"></a>nohup</h2><p>　　如果使用&amp;提交了一个后台进程，在退出时（如退出账户）该进程将会被终止。可以使用nohup命令，在退出后继续运行。nohup就是不挂起的意思 no hang up。使用nohup提交作业，如果一次提交几个作业，则将其写到一个shell脚本中，并用nohup命令来执行它<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">nohup <span class="built_in">command</span> &gt; myout.file <span class="number">2</span>&gt;&amp;<span class="number">1</span></span><br></pre></td></tr></table></figure></p>
<h2 id="u8FDB_u7A0B_u4FE1_u606F"><a href="#u8FDB_u7A0B_u4FE1_u606F" class="headerlink" title="进程信息"></a>进程信息</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#查看含有java关键字的进程信息</span></span><br><span class="line">ps -ef | grep java</span><br></pre></td></tr></table></figure>
<h2 id="u64CD_u4F5C_u7CFB_u7EDF_u4FE1_u606F"><a href="#u64CD_u4F5C_u7CFB_u7EDF_u4FE1_u606F" class="headerlink" title="操作系统信息"></a>操作系统信息</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#centos系统版本，输出CentOS release 6.3 (Final)</span></span><br><span class="line">cat /etc/issue</span><br><span class="line"><span class="comment">#打印kernel等版本信息：Linux version 2.6.32-279.el6.x86_64 (mockbuild@c6b9.bsys.dev.centos.org) (gcc version 4.4.6 20120305 (Red Hat 4.4.6-4) (GCC) ) #1 SMP Fri Jun 22 12:19:21 UTC 2012</span></span><br><span class="line">cat /proc/version</span><br><span class="line"></span><br><span class="line"><span class="comment">#centos系统位数，如果有lib64或这个目录，那操作系统就是64位的。</span></span><br><span class="line">ls /</span><br><span class="line"><span class="comment">#若为X86示意为64位系统，i386则为32位系统，uname命令可以显示内核的详细信息</span></span><br><span class="line"><span class="comment">#centos64位系统输出：Linux push1 2.6.32-279.el6.x86_64 #1 SMP Fri Jun 22 12:19:21 UTC 2012 x86_64 x86_64 x86_64 GNU/Linux</span></span><br><span class="line">uname <span class="operator">-a</span></span><br></pre></td></tr></table></figure>
<h2 id="u8FDC_u7A0B_u62F7_u8D1D"><a href="#u8FDC_u7A0B_u62F7_u8D1D" class="headerlink" title="远程拷贝"></a>远程拷贝</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#将本地/home/Administrator/file01文件拷贝到远程机器的/home/file01</span></span><br><span class="line">scp /home/Administrator/file01 root@<span class="number">192.168</span>.<span class="number">151.129</span>:/home/file01</span><br><span class="line"></span><br><span class="line"><span class="comment">#将本地/home/文件夹下的所有文件（**不包括子文件夹**）拷贝到远程机器的/root/Test/文件夹</span></span><br><span class="line">scp /home/* root@<span class="number">192.168</span>.<span class="number">151.129</span>:/root/Test/</span><br><span class="line"></span><br><span class="line"><span class="comment">#将本地/root/zhhx/files/文件夹下的所有文件（包括子文件夹）拷贝到远程机器的root@192.168.85.66:/home/test/文件夹下</span></span><br><span class="line">scp -r /root/zhhx/files root@<span class="number">192.168</span>.<span class="number">85.66</span>:/home/<span class="built_in">test</span>/</span><br><span class="line"></span><br><span class="line"><span class="comment">#将本地/usr/local/kafka_2.9.2-0.8.2.1/文件夹下的所有文件（包括子文件夹）拷贝到远程机器的/usr/local/kafka_2.9.2-0.8.2.1/文件夹</span></span><br><span class="line">scp -r /usr/<span class="built_in">local</span>/kafka_2.<span class="number">9.2</span>-<span class="number">0.8</span>.<span class="number">2.1</span>/* root@<span class="number">192.168</span>.<span class="number">241.130</span>:/usr/<span class="built_in">local</span>/kafka_2.<span class="number">9.2</span>-<span class="number">0.8</span>.<span class="number">2.1</span></span><br><span class="line"></span><br><span class="line"><span class="comment">#将远程文件夹copy到当前系统的/home文件夹下(文件名不变)</span></span><br><span class="line">scp root@<span class="number">192.168</span>.<span class="number">151.129</span>:/root/index.html /home/</span><br><span class="line"></span><br><span class="line"><span class="comment">#将远程root文件夹下所有文件（不包括子文件夹）到当前系统的/home/test文件夹下</span></span><br><span class="line">scp root@<span class="number">192.168</span>.<span class="number">151.129</span>:/root/* /home/<span class="built_in">test</span>/</span><br><span class="line"></span><br><span class="line"><span class="comment">#将远程文件夹root（子文件，子文件夹）全部拷贝到本地/home/test/目录下（在test下生成文件夹root）</span></span><br><span class="line">scp -r root@<span class="number">192.168</span>.<span class="number">151.129</span>:/root /home/<span class="built_in">test</span>/</span><br><span class="line"></span><br><span class="line"><span class="comment">#将远程文件夹root（子文件，子文件夹）全部拷贝到本地/home/test目录下(root文件夹重命名为test)</span></span><br><span class="line">scp -r root@<span class="number">192.168</span>.<span class="number">151.129</span>:/root /home/<span class="built_in">test</span></span><br></pre></td></tr></table></figure>
<h2 id="u6253_u5370_u6587_u4EF6_u8FFD_u52A0_u7684_u65B0_u5185_u5BB9"><a href="#u6253_u5370_u6587_u4EF6_u8FFD_u52A0_u7684_u65B0_u5185_u5BB9" class="headerlink" title="打印文件追加的新内容"></a>打印文件追加的新内容</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#output appended data as the file grows; -f, --follow, and --follow=descriptor are equivalent</span></span><br><span class="line">tail <span class="operator">-f</span> <span class="number">100</span></span><br></pre></td></tr></table></figure>
<h2 id="u7CFB_u7EDF_u542F_u52A8_u7EA7_u522B"><a href="#u7CFB_u7EDF_u542F_u52A8_u7EA7_u522B" class="headerlink" title="系统启动级别"></a>系统启动级别</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#centos7</span></span><br><span class="line">cat /etc/inittab </span><br><span class="line"><span class="comment"># inittab is no longer used when using systemd. </span></span><br><span class="line"><span class="comment"># </span></span><br><span class="line"><span class="comment"># ADDING CONFIGURATION HERE WILL HAVE NO EFFECT ON YOUR SYSTEM. </span></span><br><span class="line"><span class="comment"># </span></span><br><span class="line"><span class="comment"># Ctrl-Alt-Delete is handled by /etc/systemd/system/ctrl-alt-del.target </span></span><br><span class="line"><span class="comment"># </span></span><br><span class="line"><span class="comment"># systemd uses 'targets' instead of runlevels. By default, there are two main targets: </span></span><br><span class="line"><span class="comment"># </span></span><br><span class="line"><span class="comment"># multi-user.target: analogous to runlevel 3 </span></span><br><span class="line"><span class="comment"># graphical.target: analogous to runlevel 5 </span></span><br><span class="line"><span class="comment"># </span></span><br><span class="line"><span class="comment"># To set a default target, run: </span></span><br><span class="line"><span class="comment"># </span></span><br><span class="line"><span class="comment"># ln -sf /lib/systemd/system/&lt;target name&gt;.target /etc/systemd/system/default.target </span></span><br><span class="line"><span class="comment"># </span></span><br><span class="line"><span class="comment"># 以命令行的形式启动</span></span><br><span class="line">ln -sf /lib/systemd/system/multi-user.target /etc/systemd/system/default.target</span><br></pre></td></tr></table></figure>
<h2 id="u9632_u706B_u5899"><a href="#u9632_u706B_u5899" class="headerlink" title="防火墙"></a>防火墙</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#查看防火墙状态</span></span><br><span class="line">service iptables status</span><br><span class="line"></span><br><span class="line"><span class="comment">#查看防火墙随机启动时的状态</span></span><br><span class="line">&gt; chkconfig --list | grep iptables</span><br><span class="line">iptables       <span class="number">0</span>:off	<span class="number">1</span>:off	<span class="number">2</span>:on	<span class="number">3</span>:on	<span class="number">4</span>:on	<span class="number">5</span>:on	<span class="number">6</span>:off</span><br><span class="line"></span><br><span class="line"><span class="comment">#永久性关闭防火墙：</span></span><br><span class="line">chkconfig --level <span class="number">35</span> iptables off</span><br><span class="line">chkconfig iptables off</span><br><span class="line"><span class="comment">#两者的区别是</span></span><br><span class="line">--level <span class="number">35</span>之后的状态是：iptables      <span class="number">0</span>:off  <span class="number">1</span>:off	<span class="number">2</span>:on	<span class="number">3</span>:off	<span class="number">4</span>:on	<span class="number">5</span>:off	<span class="number">6</span>:off</span><br><span class="line">无--level参数的状态是：iptables       <span class="number">0</span>:off	 <span class="number">1</span>:off	<span class="number">2</span>:off	<span class="number">3</span>:off	<span class="number">4</span>:off	<span class="number">5</span>:off	<span class="number">6</span>:off</span><br><span class="line">	   </span><br><span class="line">	   </span><br><span class="line"></span><br><span class="line"><span class="comment">#临时的修改防火墙状态</span></span><br><span class="line">service iptables stop               <span class="comment">## 本次关闭防火墙</span></span><br><span class="line">service iptables restart            <span class="comment">## 重启防火墙</span></span><br><span class="line"></span><br><span class="line"><span class="comment">#Centos7中防火墙改iptables改成了firewall</span></span><br><span class="line"><span class="comment">#启动firewall</span></span><br><span class="line">systemctl start firewalld.service</span><br><span class="line"><span class="comment">#停止firewall</span></span><br><span class="line">systemctl stop firewalld.service</span><br><span class="line"><span class="comment">#禁止firewall开机启动</span></span><br><span class="line">systemctl <span class="built_in">disable</span> firewalld.service</span><br><span class="line"><span class="comment">#查看防火墙状态</span></span><br><span class="line">systemctl status firewalld.service</span><br><span class="line"></span><br><span class="line"><span class="comment">#设置防火墙开放端口</span></span><br><span class="line"><span class="comment">#修改文件/etc/sysconfig/iptables，开放22端口</span></span><br><span class="line">-A INPUT -m state --state NEW -m tcp -p tcp --dport <span class="number">22</span> -j ACCEPT</span><br><span class="line"><span class="comment">#全部修改完之后重启iptables:service iptables restart</span></span><br><span class="line"><span class="comment">#验证规则是否都已经生效：iptables -L</span></span><br></pre></td></tr></table></figure>
<h2 id="u7F51_u7EDC_u6D41_u91CF"><a href="#u7F51_u7EDC_u6D41_u91CF" class="headerlink" title="网络流量"></a>网络流量</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#安装iptraf</span></span><br><span class="line">yum -y install gcc</span><br><span class="line">yum -y install glibc</span><br><span class="line">yum -y install ncurses</span><br><span class="line">安装完毕之后 我们现在开始安装iptraf</span><br><span class="line">yum -y install iptraf</span><br><span class="line"><span class="comment">#完毕后查找下 locate iptraf</span></span><br><span class="line"><span class="comment">#查看网络流量</span></span><br><span class="line">iptraf <span class="operator">-d</span> eth0</span><br></pre></td></tr></table></figure>
<h2 id="26amp_3B"><a href="#26amp_3B" class="headerlink" title="&amp;"></a>&amp;</h2><p>　　放在启动参数后面表示设置此进程为后台进程，后台京城可以称之为job。切换到后台时会输出相关job信息，输出信息如：[1] 11319，[1]表示job ID是1,11319表示进程ID是11319。切换到后台的进程，仍然可以用ps命令查看。<br>　　进程前后台间切换可以通过bg <jobid>（background）和fg<jobid>（foreground）命令。</jobid></jobid></p>
<h2 id="u5B88_u62A4_u8FDB_u7A0B"><a href="#u5B88_u62A4_u8FDB_u7A0B" class="headerlink" title="守护进程"></a>守护进程</h2><p>　　如果一个进程永远都是以后台方式启动，并且不受到Shell退出影响而退出，一个正统的做法是将其创建为守护进程。守护进程是系统长期运行的后台进程，类似Windows服务。守护进程信息通过 ps –a 无法查看到，需要用到 –x 参数，当使用这条命令的时候，往往还附上 -j 参数以查看作业控制信息，其中TPGID一栏为-1就是守护进程。<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">&gt; ps xj</span><br><span class="line">　　PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND</span><br><span class="line">　　<span class="number">953</span> <span class="number">1190</span> <span class="number">1190</span> <span class="number">1190</span> ? -<span class="number">1</span> Ss <span class="number">1000</span> <span class="number">0</span>:<span class="number">00</span> /bin/sh /usr/bin/startkde</span><br><span class="line">　　<span class="number">1</span> <span class="number">1490</span> <span class="number">1482</span> <span class="number">1482</span> ? -<span class="number">1</span> Sl <span class="number">1000</span> <span class="number">0</span>:<span class="number">00</span> /usr/bin/VBoxClient –seamless</span><br><span class="line">　　<span class="number">1</span> <span class="number">1491</span> <span class="number">1477</span> <span class="number">1477</span> ? -<span class="number">1</span> Sl <span class="number">1000</span> <span class="number">0</span>:<span class="number">00</span> /usr/bin/VBoxClient –display</span><br></pre></td></tr></table></figure></p>
<h2 id="26amp_3B_26amp_3B__7C_7C"><a href="#26amp_3B_26amp_3B__7C_7C" class="headerlink" title="&amp;&amp; ||"></a>&amp;&amp; ||</h2><p>　　shell 在执行某个命令的时候，会返回一个返回值，该<strong>返回值保存在 shell 变量 $? 中</strong>。当 $? == 0 时，表示执行成功；当 $? == 1 时（我认为是非0的数，返回值在0-255间），表示执行失败。<br>　　有时候，下一条命令依赖前一条命令是否执行成功。如：在成功地执行一条命令之后再执行另一条命令，或者在一条命令执行失败后再执行另一条命令等。shell 提供了 &amp;&amp; 和 || 来实现命令执行控制的功能，shell 将根据 &amp;&amp; 或 || 前面命令的返回值来控制其后面命令的执行，语法格式如下：<br>　　command1 &amp;&amp; command2 [&amp;&amp; command3 …]<br>　　1. 命令之间使用 &amp;&amp; 连接，实现逻辑与的功能。<br>　　2. 只有在 &amp;&amp; 左边的命令返回真（命令返回值 $? == 0），&amp;&amp; 右边的命令才会被执行。#cmd1返回0（成功执行）后，cmd2才能够被执行<br>　　3. 只要有一个命令返回假（返回值 $? == 1），后面的命令就不会被执行，实现短路的功能</p>
<p>　　command1 || command2 [|| command3 …]<br>　　1. 命令之间使用 || 连接，实现 逻辑或的功能。<br>　　2. 只有在 || 左边的命令返回假（命令返回值 $? == 1），|| 右边的命令才会被执行。这和 c 语言中的逻辑或语法功能相同，即实现短路逻辑或操作。#cmd1返回1（成功失败）后，cmd2才能够被执行<br>　　3. 只要有一个命令返回真（命令返回值 $? == 0），后面的命令就不会被执行。即一直到返回真的地方停止执行。</p>
<h2 id="2__26gt_3B__26amp_3B1"><a href="#2__26gt_3B__26amp_3B1" class="headerlink" title="2 &gt; &amp;1"></a>2 &gt; &amp;1</h2><p>　　首先在linux中，0表示键盘输入，1表示屏幕输出，2表示错误输出，而 &gt; 表示重定向。对于 &amp;1 更准确的说应该是文件描述符 1，而1一般代表的就是STDOUT_FILENO，<br>　　/mnt/Nand3/H2000G  &gt; /dev/null  2&gt;&amp;1：把标准错误重定向到标准输出，然后扔到/dev/null下面去。通俗的说，就是把所有标准输出和标准出错都扔到垃圾桶里面。<br>　　command &gt; out.file 2 &gt; &amp;1 &amp;：将command的输出重定向到out.file文件，即输出内容不打印到屏幕上，而是输出到out.file文件中。 2&gt;&amp;1 是将标准出错重定向到标准输出，这里的标准输出已经重定向到了out.file文件，即将标准出错也输出到out.file文件中。最后一个&amp; ， 是让该命令在后台执行。<br>　　2 &gt; 1：2与 &gt; 结合代表错误重定向，而1则代表错误重定向到一个文件1，而不代表标准输出；换成2&gt;&amp;1，&amp;与1结合就代表标准输出了，就变成错误重定向到标准输出。<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#输出一个空的文件1</span></span><br><span class="line">ls <span class="number">2</span>&gt;<span class="number">1</span></span><br><span class="line"><span class="comment">#没有xxx这个文件的错误输出到了1中</span></span><br><span class="line">ls xxx <span class="number">2</span>&gt;<span class="number">1</span></span><br><span class="line"><span class="comment">#不会生成1这个文件了，不过错误跑到标准输出</span></span><br><span class="line">ls xxx <span class="number">2</span>&gt;&amp;<span class="number">1</span></span><br><span class="line"><span class="comment">#可换成 ls xxx 1&gt;out.txt 2&gt;&amp;1；重定向符号&gt;默认是1,错误和输出都传到out.txt了</span></span><br><span class="line">ls xxx &gt; out.txt <span class="number">2</span>&gt;&amp;<span class="number">1</span></span><br></pre></td></tr></table></figure></p>
<p>　　为何2&gt;&amp;1要写在后面？command &gt; file 2&gt;&amp;1。首先是command &gt; file将标准输出重定向到file中， 2&gt;&amp;1是标准错误拷贝了标准输出的行为，也就是同样被重定向到file中，最终结果就是标准输出和错误都被重定向到file中。<br>　　command 2&gt;&amp;1 &gt;file：2&gt;&amp;1 标准错误拷贝了标准输出的行为，但此时标准输出还是在终端。&gt;file 后输出才被重定向到file，但标准错误仍然保持在终端。</p>
<h2 id="u6807_u51C6_u8F93_u5165_u8F93_u51FA"><a href="#u6807_u51C6_u8F93_u5165_u8F93_u51FA" class="headerlink" title="标准输入输出"></a>标准输入输出</h2><p>　　0：标准输入 1：标准输出 2：标准错误<br><img src="/images/linux-stream.jpg" alt="linux-stream.jpg"></p>
<h2 id="u4FEE_u6539_u4E3B_u673A_u540D"><a href="#u4FEE_u6539_u4E3B_u673A_u540D" class="headerlink" title="修改主机名"></a>修改主机名</h2><p>　　CentOS6中修改主机方法，假设三台虚拟机的名字分别为：master，slave1，slave2<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 第一处 /etc/sysconfig/network</span></span><br><span class="line">NETWORKING=yes　　　　　　<span class="comment">#使用网络</span></span><br><span class="line">HOSTNAME=centos　　　　　 <span class="comment">#设置主机名称，默认为HOSTNAME=localhost.localdomain</span></span><br><span class="line"><span class="comment"># 终端中输入：hostname centos        #立即生效</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 第二处 /etc/hosts </span></span><br><span class="line">&gt; cat /etc/hosts </span><br><span class="line"><span class="number">127.0</span>.<span class="number">0.1</span> localhost.localdomain localhost</span><br><span class="line"><span class="comment"># 127.0.0.1 是本地环路地址，</span></span><br><span class="line"><span class="comment"># localhost.localdomain 是主机名(hostname)，也就是待修改的</span></span><br><span class="line"><span class="comment"># localhost 是主机名的别名（alias），它会出现在Konsole的提示符下。将第二项修改为你的主机名，第三项可选。</span></span><br><span class="line"><span class="comment"># 修改完这两处后重启，用 uname -n 命令来查看是否修改成功。</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 同时在master机器的 /etc/hosts文件中增加三行（master要根据主机名找其他两台机器，hadoop的etc配置文件用的主机名）</span></span><br><span class="line"><span class="number">192.168</span>.<span class="number">254.133</span> master</span><br><span class="line"><span class="number">192.168</span>.<span class="number">254.134</span> slave1</span><br><span class="line"><span class="number">192.168</span>.<span class="number">254.135</span> slave2</span><br><span class="line"></span><br><span class="line"><span class="comment"># slave1和slave2的/etc/hosts增加一行</span></span><br><span class="line"><span class="comment"># slave需要寻找master，否则在启动yarn后，slave机器上会没有NodeManager进程</span></span><br><span class="line"><span class="number">192.168</span>.<span class="number">254.133</span> master</span><br><span class="line"></span><br><span class="line"><span class="comment"># 重启网络服务</span></span><br><span class="line">service network restart</span><br></pre></td></tr></table></figure></p>
<p>　　在CentOS7中，有三种定义的主机名:静态的（static），瞬态的（transient），和灵活的（pretty）。“静态”主机名也称为内核主机名，是系统在启动时从/etc/hostname自动初始化的主机名。“瞬态”主机名是在系统运行时临时分配的主机名，例如，通过DHCP或mDNS服务器分配。静态主机名和瞬态主机名都遵从作为互联网域名同样的字符限制规则。而另一方面，“灵活”主机名则允许使用自由形式（包括特殊/空白字符）的主机名，以展示给终端用户（如Linuxidc）。<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">&gt; hostnamectl</span><br><span class="line">&gt; hostnamectl status</span><br><span class="line"><span class="comment">#只查看静态主机名</span></span><br><span class="line">&gt; hostnamectl --static</span><br><span class="line"><span class="comment">#只查看瞬态主机名</span></span><br><span class="line">&gt; hostnamectl --transient</span><br><span class="line"><span class="comment">#只查看灵活主机名</span></span><br><span class="line">&gt; hostnamectl --pretty</span><br><span class="line"></span><br><span class="line"><span class="comment">#同时修改所有三个主机名：静态、瞬态和灵活主机名：</span></span><br><span class="line">&gt; hostnamectl <span class="built_in">set</span>-hostname Linuxidc</span><br><span class="line"><span class="comment">#只修改特定的主机名（静态，瞬态或灵活），使用--static，--transient或--pretty选项。</span></span><br><span class="line">&gt; hostnamectl --static <span class="built_in">set</span>-hostname Linuxidc</span><br><span class="line"><span class="comment">#不必重启机器以激活永久主机名修改。上面的命令会立即修改内核主机名。注销并重新登入后在命令行提示来观察新的静态主机名。</span></span><br></pre></td></tr></table></figure></p>
<h2 id="SSH_u514D_u5BC6_u7801_u767B_u5F55"><a href="#SSH_u514D_u5BC6_u7801_u767B_u5F55" class="headerlink" title="SSH免密码登录"></a>SSH免密码登录</h2><p>　　Hadoop的namenode使用SSH协议启动namenode和datanode进程，同时datanode向namenode传递心跳信息可能也是使用SSH协议<br>　　以namenode到datanode为例子：Namenode作为客户端，要实现无密码公钥认证，连接到服务端datanode上时，需要在namenode上生成一个密钥对，包括一个公钥和一个私钥，而后将公钥复制到datanode上。当namenode通过ssh连接datanode时，datanode就会生成一个随机数并用namenode的公钥对随机数进行加密，并发送给namenode。namenode收到加密数之后再用私钥进行解密，并将解密数回传给datanode，datanode确认解密数无误之后就允许namenode进行连接了。这就是一个公钥认证过程，其间不需要用户手工输入密码。重要过程是将客户端namenode公钥复制到datanode上。<br>　　默认CentOS已经安装了OpenSSH，即使你是最小化安装也是如此。SSH的配置步骤为：<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># root用户登录</span></span><br><span class="line">gedit /etc/selinux/config </span><br><span class="line"><span class="comment"># 设置SELINUX=disabled(ssh配置如果没问题，可以省略该步骤)</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 假设从A机器连接到B机器，A机器操作（hadoop用户）</span></span><br><span class="line">&gt; ssh-keygen</span><br><span class="line"><span class="comment"># 在/home/hadoop/.ssh目录下自动生成了文件id_rsa和id_rsa.pub</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 以下两步貌似不需要执行</span></span><br><span class="line">&gt; cat id_rsa.pub &gt;&gt; authorized_keys</span><br><span class="line">&gt; chmod <span class="number">600</span> authorized_keys</span><br><span class="line"></span><br><span class="line"><span class="comment"># 将A机器公钥拷贝到B机器的/home/hadoop/.ssh目录下</span></span><br><span class="line">&gt; scp id_rsa.pub hadoop@<span class="number">192.168</span>.<span class="number">254.134</span>:.ssh/id_rsa.pub</span><br><span class="line">   </span><br><span class="line"><span class="comment"># 进入B机器的/home/hadoop/.ssh目录</span></span><br><span class="line">&gt; cat id_rsa.pub &gt;&gt; authorized_keys</span><br><span class="line"><span class="comment"># 或者执行</span></span><br><span class="line">&gt; mv id_rsa.pub authorized_keys</span><br><span class="line"></span><br><span class="line"><span class="comment"># B机器上需要的是authorized_keys，A机器上拷贝过来的id_rsa.pub可以删除。</span></span><br><span class="line"><span class="comment"># 如果是多个机器都要免密码登陆B机器，则还是使用cat id_rsa.pub &gt;&gt; authorized_keys，</span></span><br><span class="line"><span class="comment"># 将id_rsa.pub文件的内容追加到B机器的authorized_keys文件</span></span><br><span class="line"></span><br><span class="line">&gt; 执行chmod <span class="number">600</span> authorized_keys（该步骤不可省略）</span><br><span class="line">    </span><br><span class="line"><span class="comment"># 回到A机器，连接B机器</span></span><br><span class="line">&gt; ssh <span class="number">192.168</span>.<span class="number">254.134</span></span><br><span class="line"><span class="comment"># 第一次连接时会提示是否连接至B机器，直接输入yes，但是无需输入密码，</span></span><br><span class="line"><span class="comment"># 连接成功后会在A机器的/home/hadoop/.ssh目录下生成文件known_hosts）</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 执行mkdir test，此时在B机器上的/home/hadoop目录中可以看到生成了目录test。</span></span><br><span class="line"><span class="comment"># 如果删除A机器中的known_hosts，再连接B时，会成为第一次连接，回到步骤5</span></span><br></pre></td></tr></table></figure></p>
<p>　　在hadoop的配置中，均是根据hostname来进行ssh连接的，故需要在/etc/ssh中增加对应的ip hostname行信息后，再执行ssh slave1，初始连接。否则在启动./sbin/start-dfs.sh时，程序停顿如下图所示处：<img src="/images/hadoop-ssh.png" alt="hadoop-ssh.png"><br>　　在每台服务器上执行ssh-copy-id命令，自动将公钥复制到其它服务器上的authorized_keys的文件中，这里的ssh端口是18330，所以执行ssh-copy-id命令要带上端口号：<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ssh-copy-id -i ~/.ssh/id_rsa.pub <span class="string">"-p 18330 root@192.168.1.253"</span></span><br></pre></td></tr></table></figure></p>
<h2 id="u53C2_u8003_u8D44_u6599"><a href="#u53C2_u8003_u8D44_u6599" class="headerlink" title="参考资料"></a>参考资料</h2><p><a href="http://www.cnblogs.com/TianFang/archive/2013/01/23/2872645.html" target="_blank" rel="external">http://www.cnblogs.com/TianFang/archive/2013/01/23/2872645.html</a> </p>

      
    </div>
    <footer class="article-footer">
      <a data-url="http://yoursite.com/2015/12/01/linux/1.Linux系列之常用命令/" data-id="cijzzpvcv00bt1cfs6em03op4" class="article-share-link">Share</a>
      
      
  <ul class="article-tag-list"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/linux/">linux</a></li></ul>

    </footer>
  </div>
  
</article>


  
    <article id="post-groovy/1.groovy入门" class="article article-type-post" itemscope itemprop="blogPost">
  <div class="article-meta">
    <a href="/2015/12/01/groovy/1.groovy入门/" class="article-date">
  <time datetime="2015-11-30T17:00:00.000Z" itemprop="datePublished">2015-12-01</time>
</a>
    
  <div class="article-category">
    <a class="article-category-link" href="/categories/groovy/">groovy</a>
  </div>

  </div>
  <div class="article-inner">
    
    
      <header class="article-header">
        
  
    <h1 itemprop="name">
      <a class="article-title" href="/2015/12/01/groovy/1.groovy入门/">Linux系列一之常用命令</a>
    </h1>
  

      </header>
    
    <div class="article-entry" itemprop="articleBody">
      
        <h2 id="u7B80_u4ECB"><a href="#u7B80_u4ECB" class="headerlink" title="简介"></a>简介</h2><p>　　Groovy是用于Java虚拟机的一种敏捷的动态语言，它是一种成熟的面向对象编程语言，既可以用于面向对象编程，又可以用作纯粹的脚本语言。使用该种语言不必编写过多的代码，同时又具有闭包和动态语言中的其他特性。该语言特别适合与Spring的动态语言支持一起使用，设计时充分考虑了Java集成，这使 Groovy 与 Java 代码的互操作很容易。</p>
<h2 id="u5F00_u53D1_u73AF_u5883"><a href="#u5F00_u53D1_u73AF_u5883" class="headerlink" title="开发环境"></a>开发环境</h2><p>　　搭建groovy的开发环境，无需单独安装groovy，直接安装插件即可！新建一个Java Project，加入Groovy相关的包：右键项目 -&gt; Configure -&gt; Convert to Groovy Project。在项目groovy源文件下右键，New -&gt; Other -&gt; Groovy -&gt; Groovy Class。自动生成的源代码，加入main方法。groovy中默认的修饰符就是public，main方法可以去掉public。完整代码如下所示：<br><img src="/images/groov-start.png" alt="groov-start.png"><br>　　不采用修饰符public,默认存在getTitle方法，如果采用了修饰符public，getTitle方法不存在,但可以直接访问title属性<br>　　一个变量的类型在运行中随时可以改变，一切根据需要而定。如果你赋给它boolean，它接收boolean值之后就会自动把类型转变为boolean值。看下面的代码：<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><span class="line">def var=<span class="string">"hello "</span>+</span><br><span class="line">       <span class="string">"world"</span>+</span><br><span class="line">       <span class="string">",groovy!"</span></span><br><span class="line">       println var;</span><br><span class="line">       println var.class;</span><br><span class="line">       var=<span class="number">1001</span></span><br><span class="line">       println var.class</span><br><span class="line"><span class="comment">/*</span><br><span class="line">输出结果：</span><br><span class="line">hello world,groovy!</span><br><span class="line">class java.lang.String</span><br><span class="line">class java.lang.Integer</span><br><span class="line">*/</span></span><br><span class="line"></span><br><span class="line"><span class="comment">//循环</span></span><br><span class="line">def var=<span class="string">"hello "</span>+</span><br><span class="line">    <span class="string">"world"</span>+</span><br><span class="line">    <span class="string">",groovy!"</span></span><br><span class="line"><span class="function">def <span class="title">repeat</span><span class="params">(val)</span></span>&#123;</span><br><span class="line">	<span class="keyword">for</span>(i = <span class="number">0</span>; i &lt; <span class="number">5</span>; i++)&#123;</span><br><span class="line">	 println val</span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br><span class="line">repeat(var)</span><br><span class="line"><span class="comment">//输出：</span></span><br><span class="line">hello world,groovy!</span><br><span class="line">hello world,groovy!</span><br><span class="line">hello world,groovy!</span><br><span class="line">hello world,groovy!</span><br><span class="line">hello world,groovy!</span><br></pre></td></tr></table></figure></p>
<h2 id="Gstring"><a href="#Gstring" class="headerlink" title="Gstring"></a>Gstring</h2><p>　　除了标准的java.lang.String以外（用单引号括住），groovy还支持Gstring字符串类型（用双引号括住）。把上面的for循环中的语句改成：println “This is ${i}:${val}”/<em>避免了拼接字符窜</em>/<br>输出：<br>This is 0:hello world,groovy!<br>This is 1:hello world,groovy!<br>This is 2:hello world,groovy!<br>This is 3:hello world,groovy!<br>This is 4:hello world,groovy!</p>
<h2 id="u8303_u56F4"><a href="#u8303_u56F4" class="headerlink" title="范围"></a>范围</h2><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//输出 1 2 3 4 5</span></span><br><span class="line"><span class="keyword">for</span>(i in <span class="number">1</span>..<span class="number">5</span>)&#123;</span><br><span class="line">    println <span class="string">"$&#123;i&#125;"</span></span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">//输出 1 2 3 4</span></span><br><span class="line"><span class="keyword">for</span>(i in <span class="number">1</span>..&lt;<span class="number">5</span>)&#123;</span><br><span class="line">    println <span class="string">"$&#123;i&#125;"</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">//语法错误</span></span><br><span class="line"><span class="keyword">for</span>(i in <span class="number">1</span>..&lt;=<span class="number">5</span>)&#123;</span><br><span class="line">    println <span class="string">"$&#123;i&#125;"</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">//给方法指定默认参数值</span></span><br><span class="line"><span class="function">def <span class="title">repeat</span><span class="params">(val, repeat=<span class="number">3</span>)</span></span>&#123;</span><br><span class="line">    <span class="keyword">for</span>(i in <span class="number">0</span>..&lt;repeat)&#123;</span><br><span class="line">        println <span class="string">"This is $&#123;i&#125;:$&#123;val&#125;"</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">/**</span><br><span class="line"> * 输出</span><br><span class="line"> * This is 0:shc</span><br><span class="line"> * This is 1:shc</span><br><span class="line"> * This is 2:shc</span><br><span class="line"> * This is 3:shc</span><br><span class="line"> * This is 4:shc</span><br><span class="line"> */</span></span><br><span class="line">repeat(<span class="string">'shc'</span>, <span class="number">5</span>)</span><br><span class="line"><span class="comment">/**</span><br><span class="line"> * 输出</span><br><span class="line"> * This is 0:shc</span><br><span class="line"> * This is 1:shc</span><br><span class="line"> * This is 2:shc</span><br><span class="line"> */</span></span><br><span class="line">repeat(<span class="string">'shc'</span>)<span class="comment">/*未指定第二个参数*/</span></span><br></pre></td></tr></table></figure>
<h2 id="u96C6_u5408"><a href="#u96C6_u5408" class="headerlink" title="集合"></a>集合</h2><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><span class="line">def collect=[<span class="string">"a"</span>,<span class="string">"b"</span>,<span class="string">"c"</span>]</span><br><span class="line">collect.add(<span class="number">1</span>);</span><br><span class="line">collect&lt;&lt;<span class="string">"come on"</span>;</span><br><span class="line">collect[collect.size()]=<span class="number">100.0</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/*</span><br><span class="line"> * 输出[a, b, c, 1, come on, 100.0]</span><br><span class="line"> */</span></span><br><span class="line">println collect</span><br><span class="line"></span><br><span class="line"><span class="comment">/*Collection使用类似数组下标的方式进行检索：*/</span></span><br><span class="line">println collect[collect.size()-<span class="number">1</span>]</span><br><span class="line">println collect[<span class="number">5</span>]</span><br><span class="line"></span><br><span class="line"><span class="comment">/*groovy支持负索引：*/</span></span><br><span class="line">println collect[-<span class="number">1</span>]<span class="comment">//最后一个元素从-1开始，输出100.0</span></span><br><span class="line">println collect[-<span class="number">2</span>] <span class="comment">//索引其倒数第2个元素</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/*Collection支持集合运算：*/</span></span><br><span class="line">collect=collect+<span class="number">5</span> <span class="comment">//在集合中添加元素5</span></span><br><span class="line">println collect[collect.size()-<span class="number">1</span>]</span><br><span class="line"></span><br><span class="line">collect=collect-<span class="string">'a'</span> <span class="comment">//在集合中减去元素a(第1个)</span></span><br><span class="line">println collect[<span class="number">0</span>] <span class="comment">//现在第1个元素变成b了</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/*往集合中添加另一个集合或删除一个集合：*/</span></span><br><span class="line">collect=collect-collect[<span class="number">0</span>..<span class="number">4</span>] <span class="comment">//把集合中的前5个元素去掉</span></span><br><span class="line">println collect[<span class="number">0</span>] <span class="comment">//现在集合中仅有一个元素，即原来的最后一个元素</span></span><br><span class="line">println collect[-<span class="number">1</span>] <span class="comment">//也可以用负索引，证明最后一个元素就是第一个元素</span></span><br></pre></td></tr></table></figure>
<h2 id="Map"><a href="#Map" class="headerlink" title="Map"></a>Map</h2><p>　　Map是“键-值”对的集合，在groovy中，键不一定是String，可以是任何对象(实际上Groovy中的Map就是java.util.Linke dHashMap)。<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//定义一个Map: </span></span><br><span class="line">def map=[<span class="string">'name'</span>:<span class="string">'john'</span>,<span class="string">'age'</span>:<span class="number">14</span>,<span class="string">'sex'</span>:<span class="string">'boy'</span>]</span><br><span class="line"><span class="comment">//添加项：</span></span><br><span class="line">map=map+[<span class="string">'weight'</span>:<span class="number">25</span>]       <span class="comment">//添加john的体重</span></span><br><span class="line">map.put(<span class="string">'length'</span>,<span class="number">1.27</span>)      <span class="comment">//添加john的身高</span></span><br><span class="line">map.father=<span class="string">'Keller'</span>         <span class="comment">//添加john的父亲</span></span><br><span class="line"><span class="comment">//可以用两种方式检索值：</span></span><br><span class="line">println map[<span class="string">'father'</span>]       <span class="comment">//通过key作为下标索引 输出Keller</span></span><br><span class="line">println map.length          <span class="comment">//通过key作为成员名索引 输出1.27</span></span><br></pre></td></tr></table></figure></p>
<h2 id="u95ED_u5305"><a href="#u95ED_u5305" class="headerlink" title="闭包"></a>闭包</h2><p>　　闭包是用{}符号括起来的代码块，可以被单独运行或调用，也可以被命名。类似‘匿名类’或内联函数的概念。闭包中最常见的应用是对集合进行迭代，为了传递参数给闭包，闭包有一组可选的参数列表，通过“-&gt;”表示列表的结束，示例如下：<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//闭包,输出1 2 3 ， entry为参数列表</span></span><br><span class="line">[<span class="number">1</span>,<span class="number">2</span>,<span class="number">3</span>].each&#123;</span><br><span class="line"> entry -&gt; print entry + <span class="string">' '</span></span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">//等价于</span></span><br><span class="line">[<span class="number">1</span>,<span class="number">2</span>,<span class="number">3</span>].each (&#123;</span><br><span class="line"> entry -&gt; print entry + <span class="string">' '</span></span><br><span class="line">&#125;)下面定义了<span class="number">3</span>个闭包对map进行了迭代：</span><br><span class="line"></span><br><span class="line"><span class="comment">//key,value两个参数用于接受每个元素的键/值</span></span><br><span class="line"><span class="comment">//以下两种写法等效</span></span><br><span class="line">map.each(&#123;key,value-&gt;println <span class="string">"$key:$value"</span>&#125;)<span class="comment">//闭包作为一个参数传递给map的each方法</span></span><br><span class="line">map.each (&#123;key, value -&gt; println <span class="string">"$&#123;key&#125;,:$&#123;value&#125;"</span>&#125;)</span><br><span class="line"></span><br><span class="line"><span class="comment">//it是一个关键字，代表map集合的每个元素</span></span><br><span class="line">map.each&#123;println it&#125;     </span><br><span class="line">map.each(&#123; println it.getKey()+<span class="string">"--&gt;"</span>+it.getValue()&#125;)</span><br><span class="line"></span><br><span class="line"><span class="comment">//除了用于迭代之外，闭包也可以单独定义：</span></span><br><span class="line">def say=&#123;word -&gt; println <span class="string">"Hi,$word!"</span>&#125;</span><br><span class="line">say(<span class="string">'groovy'</span>) <span class="comment">//输出：Hi,groovy!</span></span><br><span class="line">say.call(<span class="string">"groovy2"</span>) <span class="comment">//输出Hi,groovy2!</span></span><br><span class="line"></span><br><span class="line"><span class="function">def <span class="title">benchmark</span><span class="params">(Integer repeat, Closure worker)</span></span>&#123;</span><br><span class="line">    start = System.currentTimeMillis()</span><br><span class="line">    <span class="comment">//注意闭包的调用方法</span></span><br><span class="line">    repeat.times &#123; item -&gt; worker(item)&#125;   <span class="comment">//repeat.times &#123; item -&gt; worker.call(item)&#125;</span></span><br><span class="line">    stop = System.currentTimeMillis()</span><br><span class="line">    <span class="keyword">return</span> stop - start</span><br><span class="line">&#125;</span><br><span class="line">def slow = benchmark(<span class="number">10000</span>)&#123; tmp -&gt;</span><br><span class="line">    (<span class="keyword">int</span>) tmp / <span class="number">2</span></span><br><span class="line">&#125;</span><br><span class="line">def fast = benchmark(<span class="number">10000</span>)&#123;</span><br><span class="line">    it.intdiv(<span class="number">2</span>)</span><br><span class="line">&#125;</span><br><span class="line">println slow + <span class="string">' '</span> + <span class="function">fast</span><br><span class="line"></span><br><span class="line">def <span class="title">benchmark</span><span class="params">(Integer repeat, Closure worker)</span></span>&#123;</span><br><span class="line"> start = System.currentTimeMillis()</span><br><span class="line"> repeat.times &#123;worker(it)&#125; <span class="comment">//times闭包默认参数为it，其值从0到9999</span></span><br><span class="line"> stop = System.currentTimeMillis()</span><br><span class="line"> <span class="keyword">return</span> stop - start</span><br><span class="line">&#125;</span><br><span class="line">def slow = benchmark(<span class="number">10000</span>)&#123;</span><br><span class="line"> (<span class="keyword">int</span>) it / <span class="number">2</span></span><br><span class="line">&#125;</span><br><span class="line">def fast = benchmark(<span class="number">10000</span>)&#123;</span><br><span class="line"> it.intdiv(<span class="number">2</span>)</span><br><span class="line">&#125;</span><br><span class="line">println slow + <span class="string">' '</span> + fast</span><br><span class="line"></span><br><span class="line"><span class="comment">//查看传入闭包的参数</span></span><br><span class="line"><span class="function">def <span class="title">aa</span><span class="params">(Closure closure)</span></span>&#123;</span><br><span class="line"> closure.getParameterTypes().size()</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">//闭包默认存在一个参数，输出1</span></span><br><span class="line">println aa&#123;&#125;</span><br><span class="line"><span class="comment">//向闭包传入一个参数，输出1 </span></span><br><span class="line">println aa&#123;one -&gt;&#125;</span><br><span class="line"><span class="comment">//向闭包传入两个参数，输出2</span></span><br><span class="line">println aa&#123;one, two -&gt;&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">//Closure 的 curry 方法返回当前闭包的一个克隆品，这个克隆品已经绑定 了一个或者多个给定的参数，参数的绑定是从左向右进行的</span></span><br><span class="line">def adder = &#123;x, y -&gt;</span><br><span class="line"> println x + <span class="string">' '</span> + y<span class="comment">//输出1 5</span></span><br><span class="line"> x + y&#125;</span><br><span class="line">def addOne = adder.curry(<span class="number">1</span>) <span class="comment">//先传入参数1</span></span><br><span class="line"><span class="function">println <span class="title">addOne</span><span class="params">(<span class="number">5</span>)</span></span><br><span class="line"></span><br><span class="line">adder </span>= &#123;x, y, z -&gt;</span><br><span class="line"> println x + <span class="string">' '</span> + y + <span class="string">' '</span> + z<span class="comment">//输出1 2 3</span></span><br><span class="line"> x + y + z&#125;</span><br><span class="line">addOne = adder.curry(<span class="number">1</span>, <span class="number">2</span>) <span class="comment">//先传入参数1 2</span></span><br><span class="line"><span class="function">println <span class="title">addOne</span><span class="params">(<span class="number">3</span>)</span><span class="comment">//输出6</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">/*</span><br><span class="line">假设你需要实现一个日志记录器，它应该支持行数的过滤，</span><br><span class="line">日志的格式化，并且输出它们到一个设备上，</span><br><span class="line">每一个记录器都应该是可配置的，办法是提供一个闭包作为每一个记录器自定义版本，</span><br><span class="line">这仍旧允许你实现应用一个过滤器，格式化和最终的日志输出，</span><br><span class="line">下列的代码显示了 curry 怎样被用来注入到自定义的记录器中：</span><br><span class="line">*/</span></span><br><span class="line"><span class="comment">//定义一个闭包，闭包的参数仍是闭包</span></span><br><span class="line">def configurator </span>= &#123;format, filter, line -&gt;</span><br><span class="line"> filter(line) ? format(line) : <span class="keyword">null</span></span><br><span class="line">&#125;</span><br><span class="line">def appender = &#123;config, append, line -&gt;</span><br><span class="line"> def out = config(line)</span><br><span class="line"> <span class="keyword">if</span>(out) append(out)</span><br><span class="line">&#125;</span><br><span class="line">def dateFormatter = &#123;line -&gt; <span class="string">'$&#123;new Date()&#125;: $&#123;line&#125;'</span>&#125;</span><br><span class="line">def debugFilter = &#123;line -&gt; line.contains(<span class="string">'debug'</span>)&#125;</span><br><span class="line">def consoleAppender = &#123;line -&gt; println line&#125;</span><br><span class="line">def myConf = configurator.curry(dateFormatter, debugFilter)</span><br><span class="line">def myLog = appender.curry(myConf, consoleAppender)</span><br><span class="line">myLog(<span class="string">'here is some debug message'</span>)</span><br><span class="line">myLog(<span class="string">'this will not be printed'</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment">/*</span><br><span class="line">我们想写一个生成积聚的函数，这个函数接收一个数字n，并 且返回一个函数，这个函数接收另外一个参数i ，并且返回n+i 的结果*/</span></span><br><span class="line"><span class="comment">//使用闭包实现</span></span><br><span class="line"><span class="function">def <span class="title">foo</span><span class="params">(n)</span></span>&#123;</span><br><span class="line"> <span class="keyword">return</span> &#123;n += it&#125;</span><br><span class="line">&#125;</span><br><span class="line">def accumulator = foo(<span class="number">1</span>)</span><br><span class="line"><span class="function">println <span class="title">accumulator</span><span class="params">(<span class="number">2</span>)</span></span><br><span class="line">println <span class="title">accumulator</span><span class="params">(<span class="number">2</span>)</span></span><br><span class="line"><span class="comment">//等价于</span></span><br><span class="line">n </span>= <span class="number">1</span></span><br><span class="line">def accumulator2 = &#123;</span><br><span class="line"> n += it&#125;</span><br><span class="line"><span class="function">println <span class="title">accumulator2</span><span class="params">(<span class="number">2</span>)</span></span><br><span class="line">println <span class="title">accumulator2</span><span class="params">(<span class="number">2</span>)</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">//闭包</span></span><br><span class="line">class Mother</span>&#123;</span><br><span class="line"> <span class="keyword">int</span> field = <span class="number">1</span></span><br><span class="line"> <span class="function"><span class="keyword">int</span> <span class="title">foo</span><span class="params">()</span></span>&#123;</span><br><span class="line">  <span class="keyword">return</span> <span class="number">2</span></span><br><span class="line"> &#125;</span><br><span class="line"> <span class="function">Closure <span class="title">birth</span><span class="params">(param)</span></span>&#123;</span><br><span class="line">  def local = <span class="number">3</span></span><br><span class="line">  def closure = &#123;caller -&gt;</span><br><span class="line">   [<span class="keyword">this</span>, field, foo(), local, param, caller, owner]</span><br><span class="line">   </span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">return</span> closure</span><br><span class="line"> &#125;</span><br><span class="line">&#125;</span><br><span class="line">Mother julia = <span class="keyword">new</span> Mother();</span><br><span class="line">closure = julia.birth(<span class="number">4</span>)</span><br><span class="line">println <span class="keyword">this</span></span><br><span class="line">context = closure.call(<span class="keyword">this</span>)</span><br><span class="line"><span class="comment">//输出</span></span><br><span class="line"><span class="comment">//Class1@757fe679</span></span><br><span class="line"><span class="comment">//Mother</span></span><br><span class="line"><span class="comment">//[Mother@2ad631, 1, 2, 3, 4, Class1@757fe679, Mother@2ad631]</span></span><br><span class="line"></span><br><span class="line">println context[<span class="number">0</span>].class.name</span><br><span class="line">println context</span><br><span class="line"><span class="keyword">assert</span> context[<span class="number">5</span>] <span class="keyword">instanceof</span> Script</span><br><span class="line"><span class="keyword">assert</span> context[<span class="number">6</span>] <span class="keyword">instanceof</span> Mother</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Counter</span></span>&#123;</span><br><span class="line"> <span class="keyword">public</span> count = <span class="number">0</span></span><br><span class="line"> </span><br><span class="line"> <span class="function">Object <span class="title">get</span><span class="params">(String name)</span></span>&#123;</span><br><span class="line">  <span class="keyword">return</span> <span class="string">'pretend value'</span></span><br><span class="line"> &#125;</span><br><span class="line"> <span class="function"><span class="keyword">void</span> <span class="title">set</span><span class="params">(String name, Object value)</span></span>&#123;</span><br><span class="line"> </span><br><span class="line">  count ++</span><br><span class="line">  <span class="comment">//name = value;</span></span><br><span class="line"> &#125;</span><br><span class="line">&#125;</span><br><span class="line">def pretender = <span class="keyword">new</span> Counter()</span><br><span class="line"><span class="keyword">assert</span> pretender.isNoField == <span class="string">'pretend value'</span></span><br><span class="line"><span class="keyword">assert</span> pretender.count == <span class="number">0</span></span><br><span class="line">pretender.isNoFieldEither = <span class="string">'just to increase counter'</span></span><br><span class="line"><span class="keyword">assert</span> pretender.count == <span class="number">1</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">//输出5 1 -- 6 2 -- 8 3 -- 11</span></span><br><span class="line">def result = (<span class="number">1</span>..<span class="number">3</span>).inject(<span class="number">5</span>) &#123;</span><br><span class="line"> sum, i -&gt;</span><br><span class="line"> print <span class="string">"$sum $i -- "</span></span><br><span class="line"> sum += i</span><br><span class="line">&#125;</span><br><span class="line">println result</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">MrBean</span></span>&#123;</span><br><span class="line"> String firstName, <span class="function">lastName</span><br><span class="line"> </span><br><span class="line"> String <span class="title">getName</span><span class="params">()</span></span>&#123;</span><br><span class="line">  <span class="keyword">return</span> <span class="string">"$firstName $lastName"</span></span><br><span class="line"> &#125;</span><br><span class="line">&#125;</span><br><span class="line">def bean = <span class="keyword">new</span> MrBean(firstName: <span class="string">'Rowan'</span>)</span><br><span class="line">bean.lastName = <span class="string">'Atkinson'</span><span class="comment">//调用setter</span></span><br><span class="line">print bean.name<span class="comment">//调用getter</span></span><br><span class="line"></span><br><span class="line">规则：当属性和相应的访问方法对调用者都是可用的时候，属性引用被解析为对访问方</span><br><span class="line">法的调用，如果只存在一种可用，这是可选的</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Pro</span></span>&#123;</span><br><span class="line"> def someProperty</span><br><span class="line"> <span class="keyword">public</span> publicField</span><br><span class="line"> <span class="keyword">private</span> privateField</span><br><span class="line">&#125;</span><br><span class="line">def obj = <span class="keyword">new</span> Pro()</span><br><span class="line">def store = []</span><br><span class="line">obj.properties.each &#123; property -&gt;</span><br><span class="line"> store += property.key</span><br><span class="line"> store += property.value</span><br><span class="line">&#125;</span><br><span class="line">println store.contains(<span class="string">'someProperty'</span>)<span class="comment">//true</span></span><br><span class="line">println store.contains(<span class="string">'publicField'</span>)<span class="comment">//false</span></span><br><span class="line">println store.contains(<span class="string">'privateField'</span>)<span class="comment">//false</span></span><br><span class="line">println store<span class="comment">//[class, class Pro, someProperty, null]</span></span><br><span class="line">println obj.properties.size()<span class="comment">//2</span></span><br></pre></td></tr></table></figure></p>
<p>　　看起来，闭包类似于方法，需要定义参数和要执行的语句，它也可以通过名称被调用。然而闭包对象（不要奇怪，闭包也是对象）可以作为参数传递（比如前面的闭包作为参数传递给了map的each方法）。而在java中，要做到这一点并不容易（也许C++中的函数指针可以，但不要忘记java中没有指针）。其次，闭包也可以不命名（当然作为代价，只能在定义闭包时执行一次），而方法不可以。</p>
<h2 id="u7C7B"><a href="#u7C7B" class="headerlink" title="类"></a>类</h2><p>　　Groovy类和java类一样，可以用标准java bean的语法定义一个groovy类，也可以使用更groovy的方式定义和使用类，这样可以少写一半以上的javabean代码：</p>
<ol>
<li>不需要public修饰符，如前面所言，groovy的默认访问修饰符就是public，如果你的groovy类成员需要public修饰，则你根本不用写它。</li>
<li>不需要类型说明，同样前面也说过，groovy也不关心变量和方法参数的具体类型。</li>
<li>不需要getter/setter方法，在很多ide（如eclipse）早就可以为序员自动产生getter/setter方法了。在groovy中，则彻底不需要getter/setter方法——所有类成员（如果是默认的public）根本不用通过getter/setter方法引用它们（当然，如果你一定要通过get/set方法访问成员属性，groovy也提供了它们）。</li>
<li>不需要构造函数，不在需要程序员声明任何构造函数，因为groovy自动提供了足够你使用的构造函数。不用担心构造函数不够多，因为实际上只需要两个构造函数（1个不带参数的默认构造函数，1个只带一个map参数的构造函数—由于是map类型，通过这个参数你可以在构造对象时任意初始化它的成员变量）。</li>
<li>不需要return，Groovy 默认返回方法的最后一行的值。Groovy中，方法不需要return来返回值吗？这个似乎很难理解。看后面的代码吧。</li>
<li>不需要()号，Groovy中方法调用可以省略()号（构造函数除外）<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//下面两句是等同的</span></span><br><span class="line">person1.setName <span class="string">'kk'</span></span><br><span class="line">person1.setName(<span class="string">'kk'</span>)</span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Person</span></span>&#123;</span><br><span class="line">	<span class="function">def name</span><br><span class="line">	def age</span><br><span class="line">	String <span class="title">toString</span><span class="params">()</span></span>&#123;</span><br><span class="line">		<span class="string">"$name, $age"</span></span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br><span class="line">def p = <span class="keyword">new</span> Person()</span><br><span class="line">p.name = <span class="string">'kk'</span></span><br><span class="line">p.setAge(<span class="number">22</span>)<span class="comment">//默认存在对应的set， get方法</span></span><br><span class="line">println p <span class="comment">//输出kk, 22，重写了toString方法</span></span><br><span class="line"></span><br><span class="line"><span class="comment">//也可以用groovy的风格做同样的事：</span></span><br><span class="line">def person2=<span class="keyword">new</span> Person([<span class="string">'name'</span>:<span class="string">'gg'</span>,<span class="string">'age'</span>:<span class="number">22</span>]) <span class="comment">//[]号可以省略</span></span><br><span class="line">println person2 <span class="comment">//输出 gg, 22</span></span><br></pre></td></tr></table></figure>
</li>
</ol>
<h2 id="u5355_u5143_u6D4B_u8BD5"><a href="#u5355_u5143_u6D4B_u8BD5" class="headerlink" title="单元测试"></a>单元测试</h2><p>　　首先添加junit的jar包，再编写测试用例：<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> org.junit.*;</span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">TestPerson</span> </span>&#123;</span><br><span class="line">       <span class="annotation">@Test</span></span><br><span class="line">       <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">testToString</span><span class="params">()</span></span>&#123;</span><br><span class="line">              Person p=<span class="keyword">new</span> Person();              <span class="comment">//注意因为groovy编译Person时默认所有属性为private</span></span><br><span class="line">              p.setName(<span class="string">"ddd"</span>);                <span class="comment">//所以用set方法设置name属性而不用p.name=”ddd”</span></span><br><span class="line">              p.setAge(<span class="number">18</span>);</span><br><span class="line">              Assert.assertEquals(<span class="string">"ddd-18"</span>, p.toString());</span><br><span class="line">       &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>　　下面使用groovy书写测试用例<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> org.junit.*;</span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">GroovyTestPerson</span> </span>&#123;</span><br><span class="line">    <span class="annotation">@Test</span></span><br><span class="line">     <span class="function"><span class="keyword">void</span> <span class="title">testToString</span><span class="params">()</span></span>&#123;</span><br><span class="line">       Person p=<span class="keyword">new</span> Person(<span class="string">"name"</span>:<span class="string">"ddd"</span>,<span class="string">"age"</span>:<span class="number">18</span>)</span><br><span class="line">       Assert.assertEquals(<span class="string">"ddd-18"</span>, p.toString())</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>　　可以看到，这里使用的完全是Groovy风格的书写方式：不需要public，使用map参数构造对象。然而当Run As a Junit Test的时候，结果跟用java编写的测试用例没有什么两样。这也充分说明了，groovy和java，除了语法不一样，本质上没有什么区别（对比.net framework中的C#和VB.net，它们除了语法不同外，本质上它们都使用CLR）。</p>
<h2 id="u53EF_u53D8_u53C2_u6570"><a href="#u53EF_u53D8_u53C2_u6570" class="headerlink" title="可变参数"></a>可变参数</h2><p>　　等同于java 5中的变长参数。首先我们定义一个变长参数的方法sum：<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">sum</span><span class="params">(<span class="keyword">int</span>... var)</span> </span>&#123;</span><br><span class="line">    def total = <span class="number">0</span></span><br><span class="line">    <span class="keyword">for</span> (i in var)</span><br><span class="line">        total += i</span><br><span class="line">    <span class="keyword">return</span> total</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">//调用sum时使用任意个数的参数：</span></span><br><span class="line"><span class="function">println <span class="title">sum</span><span class="params">(<span class="number">1</span>)</span> <span class="comment">//输出1</span></span><br><span class="line">println <span class="title">sum</span><span class="params">(<span class="number">1</span>,<span class="number">2</span>)</span> <span class="comment">//输出3</span></span><br><span class="line">println <span class="title">sum</span><span class="params">(<span class="number">1</span>,<span class="number">2</span>,<span class="number">3</span>)</span> <span class="comment">//输出6</span></span><br><span class="line">println <span class="title">sum</span><span class="params">(<span class="number">1</span>,<span class="number">1</span>,<span class="number">2</span>)</span> <span class="comment">//输出4</span></span></span><br></pre></td></tr></table></figure></p>
<h2 id="u679A_u4E3E"><a href="#u679A_u4E3E" class="headerlink" title="枚举"></a>枚举</h2><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//定义一个enum：</span></span><br><span class="line"><span class="keyword">enum</span> Day &#123;</span><br><span class="line">    SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">//在switch语句中使用</span></span><br><span class="line">def today = Day.<span class="function">SATURDAY</span><br><span class="line"><span class="title">switch</span> <span class="params">(today)</span> </span>&#123;</span><br><span class="line">  <span class="keyword">case</span> [Day.SATURDAY, Day.SUNDAY]:</span><br><span class="line">    println <span class="string">"Weekends are cool"</span></span><br><span class="line">    <span class="keyword">break</span></span><br><span class="line">  <span class="keyword">case</span> Day.MONDAY..Day.FRIDAY: <span class="comment">//a day between Monday and Friday</span></span><br><span class="line">    println <span class="string">"Boring work day"</span></span><br><span class="line">    <span class="keyword">break</span></span><br><span class="line">  <span class="keyword">default</span>:</span><br><span class="line">    println <span class="string">"Are you sure this is a valid day?"</span></span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">//注意，switch和case中可以使用任何对象，尤其是可以在case中使用List和范围，从而使分支满足多个条件。</span></span><br><span class="line"></span><br><span class="line"><span class="comment">//同java5一样，groovy支持带构造器、属性和方法的enum：</span></span><br><span class="line"><span class="keyword">enum</span> Planet &#123;</span><br><span class="line"> MERCURY(<span class="number">3.303e+23</span>, <span class="number">2.4397e6</span>),</span><br><span class="line"> VENUS(<span class="number">4.869e+24</span>, <span class="number">6.0518e6</span>),</span><br><span class="line"> EARTH(<span class="number">5.976e+24</span>, <span class="number">6.37814e6</span>),</span><br><span class="line"> MARS(<span class="number">6.421e+23</span>, <span class="number">3.3972e6</span>),</span><br><span class="line"> JUPITER(<span class="number">1.9e+27</span>,<span class="number">7.1492e7</span>),</span><br><span class="line"> SATURN(<span class="number">5.688e+26</span>, <span class="number">6.0268e7</span>),</span><br><span class="line"> URANUS(<span class="number">8.686e+25</span>, <span class="number">2.5559e7</span>),</span><br><span class="line"> NEPTUNE(<span class="number">1.024e+26</span>, <span class="number">2.4746e7</span>)</span><br><span class="line"> </span><br><span class="line"> <span class="function"><span class="keyword">double</span> mass</span><br><span class="line"> <span class="keyword">double</span> radius</span><br><span class="line"> </span><br><span class="line"> <span class="title">Planet</span><span class="params">(<span class="keyword">double</span> mass, <span class="keyword">double</span> radius)</span> </span>&#123;</span><br><span class="line">  <span class="keyword">this</span>.mass = mass;</span><br><span class="line">  <span class="keyword">this</span>.radius = radius;</span><br><span class="line"> &#125;</span><br><span class="line"> </span><br><span class="line"> <span class="function"><span class="keyword">void</span> <span class="title">printMe</span><span class="params">()</span> </span>&#123;</span><br><span class="line">  println <span class="string">"$&#123;name()&#125; has a mass of $&#123;mass&#125; "</span> + <span class="string">"and a radius of $&#123;radius&#125;"</span></span><br><span class="line"> &#125;</span><br><span class="line">&#125;</span><br><span class="line">Planet.EARTH.printMe() <span class="comment">//输出EARTH has a mass of 5.976E24 and a radius of 6378140.0</span></span><br><span class="line">println Planet.EARTH.getMass() <span class="comment">//输出5.976E24</span></span><br><span class="line">println Planet.EARTH.mass <span class="comment">//输出5.976E24</span></span><br></pre></td></tr></table></figure>
<h2 id="Elvis_u64CD_u4F5C_u7B26"><a href="#Elvis_u64CD_u4F5C_u7B26" class="headerlink" title="Elvis操作符"></a>Elvis操作符</h2><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//这是三目运算符“?:”的简单形式，三目运算符通常以这种形式出现：</span></span><br><span class="line">String displayName = name != <span class="keyword">null</span> ? name : <span class="string">"Unknown"</span>;</span><br><span class="line"><span class="comment">//在groovy中，也可以简化为（因为null在groovy中可以转化为布尔值false）：</span></span><br><span class="line">String displayName = name ? name : <span class="string">"Unknown"</span>;</span><br><span class="line"><span class="comment">//基于“不重复”的原则，可以使用elvis操作符再次简化为：</span></span><br><span class="line">String displayName = name ?: <span class="string">"Unknown"</span></span><br><span class="line"></span><br><span class="line">def name = <span class="keyword">null</span></span><br><span class="line">String displayName = name ?: <span class="string">"Unknown"</span></span><br><span class="line">println displayName <span class="comment">//输出Unknown</span></span><br></pre></td></tr></table></figure>
<h2 id="u52A8_u6001_u6027"><a href="#u52A8_u6001_u6027" class="headerlink" title="动态性"></a>动态性</h2><p>　　Groovy所有的对象都有一个元类metaClass，我们可以通过metaClass属性访问该元类。通过元类，可以为这个对象增加方法（在java中不可想象）！见下面的代码，msg是一个String，通过元类，我们为msg增加了一个String 类中所没有的方法up：<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><span class="line">def msg = <span class="string">"Hello!"</span></span><br><span class="line"><span class="comment">//输出org.codehaus.groovy.runtime.HandleMetaClass@65869953[groovy.lang.MetaClassImpl@65869953[class java.lang.String]]</span></span><br><span class="line">println msg.metaClass</span><br><span class="line"></span><br><span class="line">String.metaClass.up = &#123; delegate.toUpperCase() &#125; <span class="comment">//类比javascript</span></span><br><span class="line"><span class="comment">//输出HELLO</span></span><br><span class="line">println msg.up()</span><br><span class="line"></span><br><span class="line"><span class="comment">//通过元类还可以检索对象所拥有的方法和属性（就象反射）：</span></span><br><span class="line"><span class="comment">//methods返回List&lt;MetaMethod&gt;</span></span><br><span class="line">msg.metaClass.methods.each &#123; println it.name &#125; </span><br><span class="line"></span><br><span class="line"><span class="comment">/*输出</span><br><span class="line">up</span><br><span class="line">......</span><br><span class="line">bytes</span><br><span class="line">empty</span><br><span class="line">*/</span></span><br><span class="line"></span><br><span class="line"><span class="comment">//properties返回List&lt;MetaProperty&gt;</span></span><br><span class="line">msg.metaClass.properties.each &#123; println it.name &#125;</span><br><span class="line"><span class="comment">/*输出</span><br><span class="line">class</span><br><span class="line">bytes</span><br><span class="line">empty*/</span></span><br><span class="line"></span><br><span class="line"><span class="comment">//甚至可以看到刚才添加的up方法,可以通过元类判断有没有一个叫up的方法，然后再调用它：</span></span><br><span class="line"><span class="keyword">if</span> (msg.metaClass.respondsTo(msg, <span class="string">'up'</span>)) &#123;</span><br><span class="line">    println msg.toUpperCase()</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">//当然，也可以推断它有没有一个叫bytes的属性：</span></span><br><span class="line"><span class="keyword">if</span> (msg.metaClass.hasProperty(msg, <span class="string">'bytes'</span>)) &#123;</span><br><span class="line">    println msg.bytes.encodeBase64()</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<h2 id="swing"><a href="#swing" class="headerlink" title="swing"></a>swing</h2><p>　　到现在为止，groovy一直都在控制台窗口下工作。如果你还不满足，当然也可以使用swingbuilder来构建程序：<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> groovy.swing.SwingBuilder</span><br><span class="line"><span class="keyword">import</span> java.awt.BorderLayout</span><br><span class="line"><span class="keyword">import</span> groovy.swing.SwingBuilder</span><br><span class="line"><span class="keyword">import</span> java.awt.BorderLayout as BL</span><br><span class="line">def swing = <span class="keyword">new</span> SwingBuilder()</span><br><span class="line">count = <span class="number">0</span></span><br><span class="line">def textlabel</span><br><span class="line">def frame = swing.frame(title:<span class="string">'Frame'</span>, size:[<span class="number">400</span>,<span class="number">400</span>]) &#123;</span><br><span class="line"> borderLayout()</span><br><span class="line"> textlabel = label(</span><br><span class="line">  text:<span class="string">"Clicked $&#123;count&#125; time(s)."</span>,</span><br><span class="line">  constraints: BL.NORTH</span><br><span class="line"> )</span><br><span class="line"> button(</span><br><span class="line">  text:<span class="string">'Click Me'</span>,</span><br><span class="line">  actionPerformed: &#123;</span><br><span class="line">   count++;</span><br><span class="line">   textlabel.text = <span class="string">"Clicked $&#123;count&#125; time(s)."</span>;</span><br><span class="line">   println <span class="string">"clicked"</span></span><br><span class="line">  &#125;,</span><br><span class="line">  constraints:BorderLayout.SOUTH</span><br><span class="line"> )</span><br><span class="line">&#125;</span><br><span class="line">frame.pack()</span><br><span class="line">frame.setVisible(<span class="keyword">true</span>)</span><br></pre></td></tr></table></figure></p>
<h2 id="JVM_u4E2D_u8FD0_u884Cgroovy_u7C7B_u7684_u4E24_u79CD_u65B9_u5F0F"><a href="#JVM_u4E2D_u8FD0_u884Cgroovy_u7C7B_u7684_u4E24_u79CD_u65B9_u5F0F" class="headerlink" title="JVM中运行groovy类的两种方式"></a>JVM中运行groovy类的两种方式</h2><p>　　1. 使用groovyc编译所有的<em>.groovy为java的</em>.class文件，把这些<em>.class文件放在java类路径中，通过java类加载器来加载这些类。<br>　　2. 通过groovy的类加载器在运行时直接加载</em>.groovy文件并且生成对象，在这种方式下，没有生成任何<em>.class，但是生成了一个java.lang.Class对象的实例，也就是说，当groovy代码中包括一个new MyClass()的表达式时，并且也有一个MyClass.groovy的文件，这个文件将被解释，一个MyClass的类型将被产生并且增加到类加载器中，在代码中将像从</em>.class一样获取到MyClass对象。<br>　　图2.7介绍了转换*.groovy文件为java类的两种方法，任何一种途径产生的类都有相同的java类格式，groovy在源代码级增强java，但是在字节码是与java一样的。<a href="/images/groovy-runtime.png">groovy-runtime.png</a></p>
<h2 id="u53C2_u8003_u8D44_u6599"><a href="#u53C2_u8003_u8D44_u6599" class="headerlink" title="参考资料"></a>参考资料</h2><p><a href="http://ldlnew.blog.163.com/blog/static/10607462010542162399/" target="_blank" rel="external">http://ldlnew.blog.163.com/blog/static/10607462010542162399/</a><br><a href="http://syc001.iteye.com/blog/1022144" target="_blank" rel="external">http://syc001.iteye.com/blog/1022144</a><br><a href="http://developer.51cto.com/art/200710/58087.htm" target="_blank" rel="external">http://developer.51cto.com/art/200710/58087.htm</a></p>

      
    </div>
    <footer class="article-footer">
      <a data-url="http://yoursite.com/2015/12/01/groovy/1.groovy入门/" data-id="cijzzpvf300ef1cfsp8p5ogvi" class="article-share-link">Share</a>
      
      
  <ul class="article-tag-list"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/groovy/">groovy</a></li></ul>

    </footer>
  </div>
  
</article>


  
    <article id="post-rpc/1.RPC系列之入门" class="article article-type-post" itemscope itemprop="blogPost">
  <div class="article-meta">
    <a href="/2015/12/01/rpc/1.RPC系列之入门/" class="article-date">
  <time datetime="2015-11-30T17:00:00.000Z" itemprop="datePublished">2015-12-01</time>
</a>
    
  <div class="article-category">
    <a class="article-category-link" href="/categories/rpc/">rpc</a>
  </div>

  </div>
  <div class="article-inner">
    
    
      <header class="article-header">
        
  
    <h1 itemprop="name">
      <a class="article-title" href="/2015/12/01/rpc/1.RPC系列之入门/">RPC系列一之入门</a>
    </h1>
  

      </header>
    
    <div class="article-entry" itemprop="articleBody">
      
        <h2 id="u7B80_u4ECB"><a href="#u7B80_u4ECB" class="headerlink" title="简介"></a>简介</h2><p>　　现在web后台开发中rpc概念大行其道，同时也出现了很多优秀的框架。国外的有zeroC，国内最出名的则是神器dubbo，此外还有commonrpc、zbus等。不同的框架都有不同的优势和侧重点。但是归根结底，核心的原理都是类似的。首先rcp框架最基础组件包括两个：1. <strong>服务提供方</strong>；2. <strong>服务调用方</strong>。至于负载均衡和服务的注册与发现功能，只是在基础组件上的一个完善罢了。下面我们将通过一个简单的例子进行说明。在文章最后，会对该示例进行分析，为后面的rpc系列文章进行铺垫。</p>
<h2 id="u5B9A_u4E49_u670D_u52A1"><a href="#u5B9A_u4E49_u670D_u52A1" class="headerlink" title="定义服务"></a>定义服务</h2><p>　　下面我们将定义一个服务提供方，包括接口和实现。<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//接口</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">interface</span> <span class="title">HelloService</span> </span>&#123;</span><br><span class="line">    <span class="function">String <span class="title">hello</span><span class="params">(String name)</span></span>;</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">//实现</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">HelloServiceImpl</span> <span class="keyword">implements</span> <span class="title">HelloService</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="annotation">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> String <span class="title">hello</span><span class="params">(String name)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="string">"Hello "</span> + name;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>　　下面我们再定义一个服务的导出和引用<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">RpcFramework</span> </span>&#123;</span><br><span class="line">    <span class="comment">/**</span><br><span class="line">     * 暴露服务</span><br><span class="line">     *</span><br><span class="line">     * <span class="doctag">@param</span> service 服务实现</span><br><span class="line">     * <span class="doctag">@param</span> port 服务端口</span><br><span class="line">     * <span class="doctag">@throws</span> Exception</span><br><span class="line">     */</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">export</span><span class="params">(<span class="keyword">final</span> Object service, <span class="keyword">int</span> port)</span> <span class="keyword">throws</span> Exception </span>&#123;</span><br><span class="line">        <span class="keyword">if</span> (service == <span class="keyword">null</span>)</span><br><span class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> IllegalArgumentException(<span class="string">"service instance == null"</span>);</span><br><span class="line">        <span class="keyword">if</span> (port &lt;= <span class="number">0</span> || port &gt; <span class="number">65535</span>)</span><br><span class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> IllegalArgumentException(<span class="string">"Invalid port "</span> + port);</span><br><span class="line">        System.out.println(<span class="string">"Export service "</span> + service.getClass().getName() + <span class="string">" on port "</span> + port);</span><br><span class="line">        ServerSocket server = <span class="keyword">new</span> ServerSocket(port);</span><br><span class="line">        <span class="keyword">for</span>(;;) &#123;</span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                <span class="keyword">final</span> Socket socket = server.accept();<span class="comment">//服务器端一旦收到消息，就创建一个线程进行处理</span></span><br><span class="line">                <span class="keyword">new</span> Thread(<span class="keyword">new</span> Runnable() &#123;</span><br><span class="line">                    <span class="annotation">@Override</span></span><br><span class="line">                    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</span><br><span class="line">                        <span class="keyword">try</span> &#123;</span><br><span class="line">                            <span class="keyword">try</span> &#123;</span><br><span class="line">                                ObjectInputStream input = <span class="keyword">new</span> ObjectInputStream(socket.getInputStream());</span><br><span class="line">                                <span class="keyword">try</span> &#123;</span><br><span class="line">                                    String methodName = input.readUTF();<span class="comment">//service是服务器端提供服务的对象，但是，要通过获取到的调用方法的名称，参数类型，以及参数来选择对象的方法，并调用。获得方法的名称</span></span><br><span class="line">                                    Class&lt;?&gt;[] parameterTypes = (Class&lt;?&gt;[])input.readObject();<span class="comment">//获得参数的类型</span></span><br><span class="line">                                    Object[] arguments = (Object[])input.readObject();<span class="comment">//获得参数</span></span><br><span class="line">                                    ObjectOutputStream output = <span class="keyword">new</span> ObjectOutputStream(socket.getOutputStream());</span><br><span class="line">                                    <span class="keyword">try</span> &#123;</span><br><span class="line">                                        Method method = service.getClass().getMethod(methodName, parameterTypes);<span class="comment">//通过反射机制获得方法</span></span><br><span class="line">                                        Object result = method.invoke(service, arguments);<span class="comment">//通过反射机制获得类的方法，并调用这个方法</span></span><br><span class="line">                                        output.writeObject(result);<span class="comment">//将结果发送</span></span><br><span class="line">                                    &#125; <span class="keyword">catch</span> (Throwable t) &#123;</span><br><span class="line">                                        output.writeObject(t);</span><br><span class="line">                                    &#125; <span class="keyword">finally</span> &#123;</span><br><span class="line">                                        output.close();</span><br><span class="line">                                    &#125;</span><br><span class="line">                                &#125; <span class="keyword">finally</span> &#123;</span><br><span class="line">                                    input.close();</span><br><span class="line">                                &#125;</span><br><span class="line">                            &#125; <span class="keyword">finally</span> &#123;</span><br><span class="line">                                socket.close();</span><br><span class="line">                            &#125;</span><br><span class="line">                        &#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">                            e.printStackTrace();</span><br><span class="line">                        &#125;</span><br><span class="line">                    &#125;</span><br><span class="line">                &#125;).start();</span><br><span class="line">            &#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">                e.printStackTrace();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span><br><span class="line">     * 引用服务</span><br><span class="line">     *</span><br><span class="line">     * <span class="doctag">@param</span> &lt;T&gt; 接口泛型</span><br><span class="line">     * <span class="doctag">@param</span> interfaceClass 接口类型</span><br><span class="line">     * <span class="doctag">@param</span> host 服务器主机名</span><br><span class="line">     * <span class="doctag">@param</span> port 服务器端口</span><br><span class="line">     * <span class="doctag">@return</span> 远程服务</span><br><span class="line">     * <span class="doctag">@throws</span> Exception</span><br><span class="line">     */</span><span class="comment">//原理是通过代理，获得服务器端接口的一个“代理”的对象。对这个对象的所有操作都会调用invoke函数，在invoke函数中，是将被调用的函数名，参数列表和参数发送到服务器，并接收服务器处理的结果</span></span><br><span class="line">    <span class="annotation">@SuppressWarnings</span>(<span class="string">"unchecked"</span>)</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> &lt;T&gt; <span class="function">T <span class="title">refer</span><span class="params">(<span class="keyword">final</span> Class&lt;T&gt; interfaceClass, <span class="keyword">final</span> String host, <span class="keyword">final</span> <span class="keyword">int</span> port)</span> <span class="keyword">throws</span> Exception </span>&#123;</span><br><span class="line">        <span class="keyword">if</span> (interfaceClass == <span class="keyword">null</span>)</span><br><span class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> IllegalArgumentException(<span class="string">"Interface class == null"</span>);</span><br><span class="line">        <span class="keyword">if</span> (! interfaceClass.isInterface())</span><br><span class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> IllegalArgumentException(<span class="string">"The "</span> + interfaceClass.getName() + <span class="string">" must be interface class!"</span>);</span><br><span class="line">        <span class="keyword">if</span> (host == <span class="keyword">null</span> || host.length() == <span class="number">0</span>)</span><br><span class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> IllegalArgumentException(<span class="string">"Host == null!"</span>);</span><br><span class="line">        <span class="keyword">if</span> (port &lt;= <span class="number">0</span> || port &gt; <span class="number">65535</span>)</span><br><span class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> IllegalArgumentException(<span class="string">"Invalid port "</span> + port);</span><br><span class="line">        System.out.println(<span class="string">"Get remote service "</span> + interfaceClass.getName() + <span class="string">" from server "</span> + host + <span class="string">":"</span> + port);</span><br><span class="line">        <span class="keyword">return</span> (T) Proxy.newProxyInstance(interfaceClass.getClassLoader(), <span class="keyword">new</span> Class&lt;?&gt;[]&#123;interfaceClass&#125;, <span class="keyword">new</span> InvocationHandler() &#123;</span><br><span class="line">            <span class="function"><span class="keyword">public</span> Object <span class="title">invoke</span><span class="params">(Object proxy, Method method, Object[] arguments)</span> <span class="keyword">throws</span> Throwable </span>&#123;</span><br><span class="line">                Socket socket = <span class="keyword">new</span> Socket(host, port);</span><br><span class="line">                <span class="keyword">try</span> &#123;</span><br><span class="line">                    <span class="comment">//proxy.getClass().get</span></span><br><span class="line">                    ObjectOutputStream output = <span class="keyword">new</span> ObjectOutputStream(socket.getOutputStream());</span><br><span class="line">                    <span class="keyword">try</span> &#123;</span><br><span class="line">                        output.writeUTF(method.getName());</span><br><span class="line">                        output.writeObject(method.getParameterTypes());</span><br><span class="line">                        output.writeObject(arguments);</span><br><span class="line">                        ObjectInputStream input = <span class="keyword">new</span> ObjectInputStream(socket.getInputStream());</span><br><span class="line">                        <span class="keyword">try</span> &#123;</span><br><span class="line">                            Object result = input.readObject();</span><br><span class="line">                            <span class="keyword">if</span> (result <span class="keyword">instanceof</span> Throwable) &#123;</span><br><span class="line">                                <span class="keyword">throw</span> (Throwable) result;</span><br><span class="line">                            &#125;</span><br><span class="line">                            <span class="keyword">return</span> result;</span><br><span class="line">                        &#125; <span class="keyword">finally</span> &#123;</span><br><span class="line">                            input.close();</span><br><span class="line">                        &#125;</span><br><span class="line">                    &#125; <span class="keyword">finally</span> &#123;</span><br><span class="line">                        output.close();</span><br><span class="line">                    &#125;</span><br><span class="line">                &#125; <span class="keyword">finally</span> &#123;</span><br><span class="line">                    socket.close();</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>　　在export方法中，我们启动了一个ServerSocket用于监听指定的端口。当收到数据后，解析数据，最后通过反射的方式执行指定的方法。<br>　　在refer方法中，我们则通过java动态代理的方式，返回接口的代理对象。当我们调用接口的方法时，会运行invoke方法。在invoke方法中建立Socket连接，并向上一步的ServerSocket发送数据，等待返回结果。<br>　　最后我们实现服务提供方运行类和服务调用方运行类，如下：<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">ServerRun</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String []args)</span> <span class="keyword">throws</span> Exception </span>&#123;</span><br><span class="line">        HelloService service = <span class="keyword">new</span> HelloServiceImpl();</span><br><span class="line">        <span class="comment">//传入接口的实现</span></span><br><span class="line">        RpcFramework.export(service, <span class="number">1234</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">ClientRun</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> Exception </span>&#123;</span><br><span class="line">        <span class="comment">//实际上获取的是接口的代理对象</span></span><br><span class="line">        HelloService service = RpcFramework.refer(HelloService.class, <span class="string">"127.0.0.1"</span>, <span class="number">1234</span>);</span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; Integer.MAX_VALUE; i ++) &#123;</span><br><span class="line">            <span class="comment">//通过代理的invoke方法，连接远程服务器，实现远程调用</span></span><br><span class="line">            String hello = service.hello(<span class="string">"World"</span> + i);</span><br><span class="line">            System.out.println(hello);</span><br><span class="line">            Thread.sleep(<span class="number">1000</span>);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>　　运行以上代码，则可看到效果。这样我们就完成了一个简单的rpc调用。代码下载地址：<a href="/code/rpc-demo.zip">rpc-demo.zip</a></p>
<h2 id="u5206_u6790"><a href="#u5206_u6790" class="headerlink" title="分析"></a>分析</h2><p>　　接下来我们开始分析以上代码，首先罗列出其问题：<br>　　1. 每新增一个服务，就需要调用一次RpcFramework.export方法，每次的端口都必须不同，能否多个服务共享一个端口。<br>　　2. 采用BIO的模式，存在阻塞等性能问题<br>　　3. 服务调用方能否动态的获取服务提供方的地址<br>　　4. 未考虑粘包掉包的问题<br>　　5. 缺少服务提供方和调用方的数据交换协议</p>

      
    </div>
    <footer class="article-footer">
      <a data-url="http://yoursite.com/2015/12/01/rpc/1.RPC系列之入门/" data-id="cijzzpv5j003k1cfsjoanol4g" class="article-share-link">Share</a>
      
      
  <ul class="article-tag-list"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/java/">java</a></li><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/rpc/">rpc</a></li></ul>

    </footer>
  </div>
  
</article>


  
    <article id="post-java/14.SPI概述" class="article article-type-post" itemscope itemprop="blogPost">
  <div class="article-meta">
    <a href="/2015/11/29/java/14.SPI概述/" class="article-date">
  <time datetime="2015-11-29T04:21:36.000Z" itemprop="datePublished">2015-11-29</time>
</a>
    
  <div class="article-category">
    <a class="article-category-link" href="/categories/java/">java</a>
  </div>

  </div>
  <div class="article-inner">
    
    
      <header class="article-header">
        
  
    <h1 itemprop="name">
      <a class="article-title" href="/2015/11/29/java/14.SPI概述/">Java SPI机制</a>
    </h1>
  

      </header>
    
    <div class="article-entry" itemprop="articleBody">
      
        <h3 id="u7B80_u4ECB"><a href="#u7B80_u4ECB" class="headerlink" title="简介"></a>简介</h3><p>　　SPI的全名为Service Provider Interface，究其思想，其实是和回调差不多。回调的思想是在我们调用API的时候，可以自己写一段逻辑代码，传入到API里面，API内部在合适的时候会调用它，从而实现某种程度的定制。 </p>
<p>　　我们系统里抽象的各个模块，往往有很多不同的实现方案，比如日志模块的方案，xml解析模块等。面向的对象的设计里，我们一般推荐模块之间基于接口编程，模块之间不对实现类进行硬编码。一旦代码里涉及具体的实现类，就违反了可拔插的原则，如果需要替换一种实现，就需要修改代码。</p>
<p>　　为了实现在模块装配的时候能不在程序里动态指明，这就需要一种服务发现机制spi：为某个接口寻找服务实现的机制。有点类似IOC的思想，就是将装配的控制权移到程序之外，在模块化设计中这个机制尤其重要。</p>
<h3 id="u89C4_u5219"><a href="#u89C4_u5219" class="headerlink" title="规则"></a>规则</h3><p>　　当服务的提供者提供了服务接口的一种实现之后，在jar包的META-INF/services/目录里同时创建一个以服务接口命名的文件。该文件里就是实现该服务接口的具体实现类。而当外部程序装配这个模块的时候，就能通过该jar包META-INF/services/里的配置文件找到具体的实现类名，并装载实例化，完成模块的注入。 </p>
<p>基于这样一个约定就能很好的找到服务接口的实现类，而不需要再代码里制定。</p>
<h3 id="u793A_u4F8B"><a href="#u793A_u4F8B" class="headerlink" title="示例"></a>示例</h3><p>定义查找接口com.openim.spi.ISearch</p>
<pre><code class="java"><span class="keyword">public</span> <span class="class"><span class="keyword">interface</span> <span class="title">ISearch</span> </span>{
    <span class="function">String <span class="title">hello</span><span class="params">(String name)</span></span>;
}
</code></pre>
<p>实现接口com.openim.spi.FileSearch</p>
<pre><code class="java"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">FileSearch</span> <span class="keyword">implements</span> <span class="title">ISearch</span> </span>{
    <span class="meta">@Override</span>
    <span class="function"><span class="keyword">public</span> String <span class="title">hello</span><span class="params">(String name)</span> </span>{
        <span class="keyword">return</span> <span class="string">"FileSearch"</span>;
    }
}
</code></pre>
<p>实现接口com.openim.spi.FileSearch</p>
<pre><code class="java"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">DBSearch</span> <span class="keyword">implements</span> <span class="title">ISearch</span> </span>{
    <span class="meta">@Override</span>
    <span class="function"><span class="keyword">public</span> String <span class="title">hello</span><span class="params">(String name)</span> </span>{
        <span class="keyword">return</span> <span class="string">"DBSearch"</span>;
    }
}
</code></pre>
<p>定义测试类com.openim.spi.Main</p>
<pre><code class="java"><span class="keyword">import</span> java.util.Iterator;
<span class="keyword">import</span> java.util.ServiceLoader;

<span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Main</span> </span>{
    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>{
        ServiceLoader&lt;ISearch&gt; s = ServiceLoader.load(ISearch.class);
        Iterator&lt;ISearch&gt; searchs = s.iterator();
        <span class="keyword">while</span> (searchs.hasNext()) {
            ISearch curSearch = searchs.next();
            String result = curSearch.hello(<span class="string">"test"</span>);
            System.out.println(result);
        }
    }
}
</code></pre>
<p>最后创建在META-INF/searvices下创建文件com.openim.spi.ISearch，并输入如下内容</p>
<pre><code class="java">com.openim.spi.FileSearch
com.openim.spi.DBSearch
</code></pre>
<p>运行Main方法，输出如下：<br>FileSearch<br>DBSearch</p>
<p>项目结构如图所示：<br><img src="/images/spi.png" alt="项目结构图"></p>
<h3 id="dubbo_u6269_u5C55"><a href="#dubbo_u6269_u5C55" class="headerlink" title="dubbo扩展"></a>dubbo扩展</h3><p>　　在dubbo框架中，作者对该机制进行了扩展，首先，定义了SPI注解，只有在接口上打了@SPI注解的接口类才会去查找扩展点实现，查找顺序为META-INF/dubbo/internal/   （dubbo内部实现的各种扩展都放在了这个目录）、META-INF/dubbo/、META-INF/services/<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;以Protocol接口为例，接口打上SPI注解，默认扩展点名字为dubbo</p>
<pre><code class="java"><span class="meta">@SPI</span>(<span class="string">"dubbo"</span>)
<span class="keyword">public</span> <span class="class"><span class="keyword">interface</span> <span class="title">Protocol</span></span>{

}
</code></pre>
<p>dubbo中内置实现了各种协议如：DubboProtocol HessianProtocol RmiProtocol<br><img src="/images/dubbo-protocol-impl.png" alt="协议"><br>Dubbo默认rpc模块默认protocol实现DubboProtocol，key为dubbo<br><img src="/images/dubbo-protocol.png" alt="默认protocol"></p>

      
    </div>
    <footer class="article-footer">
      <a data-url="http://yoursite.com/2015/11/29/java/14.SPI概述/" data-id="cijzzpvea00di1cfsp2um05at" class="article-share-link">Share</a>
      
      
  <ul class="article-tag-list"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/dubbo/">dubbo</a></li><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/spi/">spi</a></li></ul>

    </footer>
  </div>
  
</article>


  
    <article id="post-java/1.AOP系列之概述" class="article article-type-post" itemscope itemprop="blogPost">
  <div class="article-meta">
    <a href="/2015/11/01/java/1.AOP系列之概述/" class="article-date">
  <time datetime="2015-11-01T03:20:36.000Z" itemprop="datePublished">2015-11-01</time>
</a>
    
  <div class="article-category">
    <a class="article-category-link" href="/categories/java/">java</a>
  </div>

  </div>
  <div class="article-inner">
    
    
      <header class="article-header">
        
  
    <h1 itemprop="name">
      <a class="article-title" href="/2015/11/01/java/1.AOP系列之概述/">AOP系列一之概述</a>
    </h1>
  

      </header>
    
    <div class="article-entry" itemprop="articleBody">
      
        <h2 id="u7B80_u4ECB"><a href="#u7B80_u4ECB" class="headerlink" title="简介"></a>简介</h2><p>　　AOP(Aspect Oriented Programming)，是面向切面编程的技术。AOP基于IoC基础，是对OOP的有益补充。AOP之所以能得到广泛应用，主要是因为它将应用系统拆分分了2个部分：核心业务逻辑（Core business concerns）及横向的通用逻辑，也就是所谓的切面Crosscutting enterprise concerns。例如，所有大中型应用都要涉及到的持久化管理（Persistent）、事务管理（Transaction Management）、权限管理（Privilege Management）、日志管理（Logging）和调试管理（Debugging）等。这样，使用AOP技术时，可以让开发人员只专注核心业务，而通用逻辑则使用AOP技术进行横向切入，由专人去处理这些通用逻辑，会使得任务简单明了，提高开发和调试的效率。 </p>
<h2 id="u5B9E_u73B0_u65B9_u5F0F"><a href="#u5B9E_u73B0_u65B9_u5F0F" class="headerlink" title="实现方式"></a>实现方式</h2><p>　　通过下图，我们可以看到从三个层面来实现AOP。<br><img src="/images/aop.jpg" alt="aop.jpg"><br>　　在<strong>编译期修改源代码</strong>，在运行期<strong>字节码加载前修改字节码</strong>或<strong>字节码加载后动态创建代理类的字节码</strong>，以下是各种实现机制的比较。<br><img src="/images/aop-func.png" alt="aop-func.png"></p>
<h2 id="u57FA_u672C_u6982_u5FF5"><a href="#u57FA_u672C_u6982_u5FF5" class="headerlink" title="基本概念"></a>基本概念</h2><ul>
<li><strong>切面</strong>(aspect)：用来切插业务方法的类。</li>
<li><strong>切入点</strong>(pointcut)：一个（组）基于正则表达式的表达式，说他本身是一个表达式，但是他是基于正则语法的。通常一个pointcut，会选取程序中的某些我们感兴趣的执行点，或者说是程序执行点的集合。。</li>
<li><strong>连接点</strong>(joinpoint)：程序执行过程中明确的点，如方法的调用或特定的异常被抛出(如某个业务方法)。</li>
<li><strong>目标对象</strong>(target object)：被代理对象。</li>
<li><strong>AOP代理</strong>(aop proxy)：代理对象。</li>
<li><strong>通知</strong>(advice)：在切面类中，声明对业务方法做额外处理的方法(要切入的逻辑)。此处译为增加更合适，因为它是对原有代码功能的一种“增强”。再说，CGLib 中也有一个 Enhancer 类，它就是一个增强类。</li>
<li><strong>前置通知</strong>(before advice)：在切入点（业务代码）之前执行。</li>
<li><strong>后置通知</strong>(after returning advice)：在切入点（业务代码）执行完成后，执行通知。</li>
<li><strong>环绕通知</strong>(around advice)：包围切入点，调用方法前后完成自定义行为。</li>
<li><strong>异常通知</strong>(after throwing advice)：在切入点抛出异常后，执行通知。</li>
</ul>
<p>　　织入器通过在切面中定义pointcut来搜索目标（被代理类）的JoinPoint(切入点)，然后把要切入的逻辑（Advice）织入到目标对象里，生成代理类。</p>
<h2 id="u5B9E_u73B0_u65B9_u5F0F-1"><a href="#u5B9E_u73B0_u65B9_u5F0F-1" class="headerlink" title="实现方式"></a>实现方式</h2><ul>
<li><strong>静态织入(Compile Time Weaving, CTW)</strong>：即在编译期，将需要增加的代码逻辑织入到源代码中，这种方式侵入性强，影响了原有代码的逻辑，该种方式常用的类库为Aspectj</li>
<li><strong>类加载期织入(Load Time Weaving, LTW)</strong>：即通过特殊的类加载器，在类字节码加载到JVM时织入切面，未对原业务代码进行侵入，同时也保证了良好的执行效率，该种方式常用的类库为Aspectj(需要编写 aop.xml 文件并在启动 Java 时带上参数-javaagent，本文不再涉及)</li>
<li><strong>动态织入</strong>：即通过动态代理的方式进行织入，常用的组件有JDK动态代理机制，通过实现InvocationHandler接口，这种方式需要定义接口。这时，可以利用CGLIB包。CGLIB是针对类来实现代理的，它的原理是对指定的目标类生成一个子类，并覆盖其中方法实现增强，采用的是继承的方式。此外AspectJ也可以在运行期动态代理的方式织入切面(需要用Java编写切面并加以注释)</li>
</ul>
<h2 id="u7CFB_u5217_u6587_u7AE0"><a href="#u7CFB_u5217_u6587_u7AE0" class="headerlink" title="系列文章"></a>系列文章</h2><p><a href="/../1.AOP系列之概述/">1. AOP系列之概述</a><br><a href="/../2.AOP系列之AspectJ/">2. AOP系列之AspectJ</a><br><a href="/../3.AOP系列之JDK Proxy/">3. AOP系列之JDK Proxy</a><br><a href="/../4.AOP系列之CGLIB/">4. AOP系列之CGLIB</a><br><a href="/../5.AOP系列之CGLIB源码学习/">5. AOP系列之CGLIB源码学习</a><br><a href="/../6.AOP系列之Spring AOP/">6. AOP系列之Spring AOP</a><br><a href="/../7.AOP系列之Spring AspectJ/">7. AOP系列之Spring AspectJ</a></p>

      
    </div>
    <footer class="article-footer">
      <a data-url="http://yoursite.com/2015/11/01/java/1.AOP系列之概述/" data-id="cijzzpvet00e51cfshckcanvo" class="article-share-link">Share</a>
      
      
  <ul class="article-tag-list"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/aop/">aop</a></li><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/java/">java</a></li></ul>

    </footer>
  </div>
  
</article>


  
  
    <nav id="page-nav">
      <a class="extend prev" rel="prev" href="/page/14/">&laquo; Prev</a><a class="page-number" href="/">1</a><span class="space">&hellip;</span><a class="page-number" href="/page/13/">13</a><a class="page-number" href="/page/14/">14</a><span class="page-number current">15</span>
    </nav>
  
</section>
        
          <aside id="sidebar">
  
    
  <div class="widget-wrap">
    <h3 class="widget-title">Categories</h3>
    <div class="widget">
      <ul class="category-list"><li class="category-list-item"><a class="category-list-link" href="/categories/cache/">cache</a><span class="category-list-count">3</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/database/">database</a><span class="category-list-count">13</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/docker/">docker</a><span class="category-list-count">6</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/gis/">gis</a><span class="category-list-count">4</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/git/">git</a><span class="category-list-count">2</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/go/">go</a><span class="category-list-count">1</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/gradle/">gradle</a><span class="category-list-count">1</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/groovy/">groovy</a><span class="category-list-count">1</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/hadoop/">hadoop</a><span class="category-list-count">1</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/java/">java</a><span class="category-list-count">18</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/linux/">linux</a><span class="category-list-count">4</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/log/">log</a><span class="category-list-count">11</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/mongodb/">mongodb</a><span class="category-list-count">14</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/mq/">mq</a><span class="category-list-count">6</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/mybatis/">mybatis</a><span class="category-list-count">9</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/netty/">netty</a><span class="category-list-count">1</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/nginx/">nginx</a><span class="category-list-count">3</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/nio/">nio</a><span class="category-list-count">19</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/nodejs/">nodejs</a><span class="category-list-count">1</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/redis/">redis</a><span class="category-list-count">6</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/rpc/">rpc</a><span class="category-list-count">14</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/spring/">spring</a><span class="category-list-count">5</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/tomcat/">tomcat</a><span class="category-list-count">2</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/zookeeper/">zookeeper</a><span class="category-list-count">2</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/杂项/">杂项</a><span class="category-list-count">2</span></li></ul>
    </div>
  </div>

  
    
  <div class="widget-wrap">
    <h3 class="widget-title">Tags</h3>
    <div class="widget">
      <ul class="tag-list"><li class="tag-list-item"><a class="tag-list-link" href="/tags/aop/">aop</a><span class="tag-list-count">8</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/aspectj/">aspectj</a><span class="tag-list-count">3</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/cache/">cache</a><span class="tag-list-count">3</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/classloader/">classloader</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/common-loggings/">common-loggings</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/commonjs/">commonjs</a><span class="tag-list-count">4</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/database/">database</a><span class="tag-list-count">10</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/docker/">docker</a><span class="tag-list-count">6</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/dubbo/">dubbo</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/fastdfs/">fastdfs</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/gclib/">gclib</a><span class="tag-list-count">2</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/geohash/">geohash</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/gis/">gis</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/git/">git</a><span class="tag-list-count">2</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/go/">go</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/gradle/">gradle</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/groovy/">groovy</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/hadoop/">hadoop</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/hessisan/">hessisan</a><span class="tag-list-count">3</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/java/">java</a><span class="tag-list-count">48</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/javassist/">javassist</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/kafka/">kafka</a><span class="tag-list-count">3</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/linux/">linux</a><span class="tag-list-count">4</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/log/">log</a><span class="tag-list-count">11</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/log4j/">log4j</a><span class="tag-list-count">4</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/logback/">logback</a><span class="tag-list-count">5</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/map/">map</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/memecached/">memecached</a><span class="tag-list-count">2</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/mina/">mina</a><span class="tag-list-count">5</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/mongodb/">mongodb</a><span class="tag-list-count">14</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/mq/">mq</a><span class="tag-list-count">6</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/mqtt/">mqtt</a><span class="tag-list-count">2</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/mybatis/">mybatis</a><span class="tag-list-count">9</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/netty/">netty</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/nginx/">nginx</a><span class="tag-list-count">3</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/nio/">nio</a><span class="tag-list-count">5</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/nodejs/">nodejs</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/postgresql/">postgresql</a><span class="tag-list-count">2</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/protobuf/">protobuf</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/proxy/">proxy</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/push/">push</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/rabbitmq/">rabbitmq</a><span class="tag-list-count">3</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/redis/">redis</a><span class="tag-list-count">6</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/rpc/">rpc</a><span class="tag-list-count">14</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/sitemesh/">sitemesh</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/sld/">sld</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/slf4j/">slf4j</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/socket/">socket</a><span class="tag-list-count">7</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/spatialite-for-android/">spatialite for android</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/spi/">spi</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/spring/">spring</a><span class="tag-list-count">13</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/tomcat/">tomcat</a><span class="tag-list-count">2</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/transaction/">transaction</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/web/">web</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/xSocket/">xSocket</a><span class="tag-list-count">7</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/zbus/">zbus</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/zookeeper/">zookeeper</a><span class="tag-list-count">2</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/数据结构/">数据结构</a><span class="tag-list-count">2</span></li></ul>
    </div>
  </div>

  
    
  <div class="widget-wrap">
    <h3 class="widget-title">Tag Cloud</h3>
    <div class="widget tagcloud">
      <a href="/tags/aop/" style="font-size: 15.38px;">aop</a> <a href="/tags/aspectj/" style="font-size: 11.54px;">aspectj</a> <a href="/tags/cache/" style="font-size: 11.54px;">cache</a> <a href="/tags/classloader/" style="font-size: 10px;">classloader</a> <a href="/tags/common-loggings/" style="font-size: 10px;">common-loggings</a> <a href="/tags/commonjs/" style="font-size: 12.31px;">commonjs</a> <a href="/tags/database/" style="font-size: 16.92px;">database</a> <a href="/tags/docker/" style="font-size: 13.85px;">docker</a> <a href="/tags/dubbo/" style="font-size: 10px;">dubbo</a> <a href="/tags/fastdfs/" style="font-size: 10px;">fastdfs</a> <a href="/tags/gclib/" style="font-size: 10.77px;">gclib</a> <a href="/tags/geohash/" style="font-size: 10px;">geohash</a> <a href="/tags/gis/" style="font-size: 10px;">gis</a> <a href="/tags/git/" style="font-size: 10.77px;">git</a> <a href="/tags/go/" style="font-size: 10px;">go</a> <a href="/tags/gradle/" style="font-size: 10px;">gradle</a> <a href="/tags/groovy/" style="font-size: 10px;">groovy</a> <a href="/tags/hadoop/" style="font-size: 10px;">hadoop</a> <a href="/tags/hessisan/" style="font-size: 11.54px;">hessisan</a> <a href="/tags/java/" style="font-size: 20px;">java</a> <a href="/tags/javassist/" style="font-size: 10px;">javassist</a> <a href="/tags/kafka/" style="font-size: 11.54px;">kafka</a> <a href="/tags/linux/" style="font-size: 12.31px;">linux</a> <a href="/tags/log/" style="font-size: 17.69px;">log</a> <a href="/tags/log4j/" style="font-size: 12.31px;">log4j</a> <a href="/tags/logback/" style="font-size: 13.08px;">logback</a> <a href="/tags/map/" style="font-size: 10px;">map</a> <a href="/tags/memecached/" style="font-size: 10.77px;">memecached</a> <a href="/tags/mina/" style="font-size: 13.08px;">mina</a> <a href="/tags/mongodb/" style="font-size: 19.23px;">mongodb</a> <a href="/tags/mq/" style="font-size: 13.85px;">mq</a> <a href="/tags/mqtt/" style="font-size: 10.77px;">mqtt</a> <a href="/tags/mybatis/" style="font-size: 16.15px;">mybatis</a> <a href="/tags/netty/" style="font-size: 10px;">netty</a> <a href="/tags/nginx/" style="font-size: 11.54px;">nginx</a> <a href="/tags/nio/" style="font-size: 13.08px;">nio</a> <a href="/tags/nodejs/" style="font-size: 10px;">nodejs</a> <a href="/tags/postgresql/" style="font-size: 10.77px;">postgresql</a> <a href="/tags/protobuf/" style="font-size: 10px;">protobuf</a> <a href="/tags/proxy/" style="font-size: 10px;">proxy</a> <a href="/tags/push/" style="font-size: 10px;">push</a> <a href="/tags/rabbitmq/" style="font-size: 11.54px;">rabbitmq</a> <a href="/tags/redis/" style="font-size: 13.85px;">redis</a> <a href="/tags/rpc/" style="font-size: 19.23px;">rpc</a> <a href="/tags/sitemesh/" style="font-size: 10px;">sitemesh</a> <a href="/tags/sld/" style="font-size: 10px;">sld</a> <a href="/tags/slf4j/" style="font-size: 10px;">slf4j</a> <a href="/tags/socket/" style="font-size: 14.62px;">socket</a> <a href="/tags/spatialite-for-android/" style="font-size: 10px;">spatialite for android</a> <a href="/tags/spi/" style="font-size: 10px;">spi</a> <a href="/tags/spring/" style="font-size: 18.46px;">spring</a> <a href="/tags/tomcat/" style="font-size: 10.77px;">tomcat</a> <a href="/tags/transaction/" style="font-size: 10px;">transaction</a> <a href="/tags/web/" style="font-size: 10px;">web</a> <a href="/tags/xSocket/" style="font-size: 14.62px;">xSocket</a> <a href="/tags/zbus/" style="font-size: 10px;">zbus</a> <a href="/tags/zookeeper/" style="font-size: 10.77px;">zookeeper</a> <a href="/tags/数据结构/" style="font-size: 10.77px;">数据结构</a>
    </div>
  </div>

  
    
  <div class="widget-wrap">
    <h3 class="widget-title">Archives</h3>
    <div class="widget">
      <ul class="archive-list"><li class="archive-list-item"><a class="archive-list-link" href="/archives/2016/01/">January 2016</a><span class="archive-list-count">67</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2015/12/">December 2015</a><span class="archive-list-count">81</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2015/11/">November 2015</a><span class="archive-list-count">2</span></li></ul>
    </div>
  </div>

  
    
  <div class="widget-wrap">
    <h3 class="widget-title">Recents</h3>
    <div class="widget">
      <ul>
        
          <li>
            <a href="/2016/01/30/资料/">(no title)</a>
          </li>
        
          <li>
            <a href="/2016/01/30/java/13.Classloader系列一/">ClassLoader系列一</a>
          </li>
        
          <li>
            <a href="/2016/01/29/hadoop/1.hadoop系列之源码编译/">hadoop系列一之源码编译</a>
          </li>
        
          <li>
            <a href="/2016/01/29/go/1.GO系列之入门/">Go系列一之入门</a>
          </li>
        
          <li>
            <a href="/2016/01/28/tomcat/2.tomcat性能优化/">tomcat性能优化</a>
          </li>
        
      </ul>
    </div>
  </div>

  
</aside>
        
      </div>
      <footer id="footer">
  
  <div class="outer">
    <div id="footer-info" class="inner">
      &copy; 2016 John Doe<br>
      Powered by <a href="http://hexo.io/" target="_blank">Hexo</a>
    </div>
  </div>
</footer>
    </div>
    <nav id="mobile-nav">
  
    <a href="/" class="mobile-nav-link">Home</a>
  
    <a href="/archives" class="mobile-nav-link">Archives</a>
  
</nav>
    


<script src="http://libs.baidu.com/jquery/2.0.3/jquery.min.js"></script>


  <link rel="stylesheet" href="/fancybox/jquery.fancybox.css" type="text/css">
  <script src="/fancybox/jquery.fancybox.pack.js" type="text/javascript"></script>


<script src="/js/script.js" type="text/javascript"></script>

  </div>
</body>
</html>